硬件设计论坛 电子论坛网站
如何培养硬件设计工程师——转自好网
如何培养一个硬件设计工程师。我觉得这是个长期的工作,不是那么容易完成的。通常很多单位都会这样,即招到一个硬件设计工程师,在毫无基础的情况下,直接让他设计一个FPGA或者DSP板子。然后所谓培训,只是软件熟悉熟悉,比如mentor的工具,DXP或者allegro。但是只是会做原理图和会画版图,远远达不到一个硬件工程师的要求。而且这种方式有些饮鸩止渴的感觉。以后这个人肯定水平无法上去。因为硬件,也是要用心去学的,硬件不是画出来的,是用脑子想出来的。比如做FPGA的原理图,一个FPGA那么复杂,手册N多,怎么可能一个月时间做出原理图呢,除非是天才或者每天加班24小时。更有甚者直接要求一个月做出一个系统板,即包括FPGA、DSP等。于是惶恐中设计出一个板子,然后交付PCB设计小组,PCB设计小组拿到的是网表而非原理图本身,他们大多数是不理解原理图的,也没时间理解,因为一看列表,那么多任务排着呢。于是十多天画个系统板,然后开始投板,装焊,调试。最后我敢保证,大多数板子是调试不出结果来的。于是就去外协,认为自己单位做不了。我个人觉得,是因为培养硬件工程师的方法不对。一个硬件工程师,我觉得应该具备能够设计以FPGA、DSP、ARM、单片机为核心的数字系统控制或者信号处理板,以及具备板子的仿真、分析、调试能力。具备射频以及高频设计能力,这才能真正称为硬件工程师。不但会上述软件,而且精通ADS、Hspice、Q3D、hyperlink、cadence等软件仿真能力。具备能够写出基于硬件调试的verilog、VHDL、C、汇编语言的能力。这些能力需要起码一年时间来训练。可以让他先做一个单片机最小系统板,期间要多多看手册,多多看论坛或者去网上搜单片机的知识,我相信大学毕业真正掌握单片机的人不多吧。做原理图和板子过程中,学会仿真软件,同时对有些关键信号做一些简单的仿真分析。在投板之后,开始学习如何写出规范的基于硬件调试的C以及汇编语言。等板子回来之后,尽量调通,如果调不通,就去找老师傅帮忙,相信一个单片机最小系统应该很容易调通。而且不要小看这最小系统,调试期间能够学会很多东西。补充一下,在设计原理图,版图以及调试方案的时候,最好让组内的老师傅帮忙做一些评审,否则是学不到太多东西的。也不知道自己犯了什么低级错误。当一个单片机通过,就可以尝试FPGA或者DSP或者ARM了。这个就看具体需要,如果你是做手机系统板,就偏重于ARM,如果是做信号处理或者密集计算,就偏重于FPGA或者DSP。还是走刚才的路子,只是路要长很多,因为这些手册、开发环境、以及板子的难度要大太多。就连FPGA的版图库建模等,也没那么简单,这里可以参考这些芯片推荐的开发板设计,很多高级芯片都会配套有PCB设计规范,一定要耐心好好看看。白天设计,晚上学习,不要急于投板,投板快的,不见得是高手,最后调试最成功的,才是牛人。最后调试成功又能学到最多的,才是收获最大的。这些做过之后,就可以尝试开始做射频板,比如可以做一个最简单的2.4GHz的射频收发系统,如果对射频不熟悉,可以先用单片电路设计,然后逐渐扩展到用功放、LNA、频综等进行设计。在设计中,仿真就相对重要多了,重点用ADS结合HFSS软件进行仿真,同时学会做版图仿真,因为仿真是保证高频电路前期设计的最重要方法。在设计完成后,高频电路调试,就不像低频电路那么简单了,要预留出足够的SMA头以便采用VNA或者频谱分析仪进行测试,因为射频电路板的很多问题都是无法预知的,高频的电磁兼容等问题很严重。这时候就靠时间和经验了。然后逐渐扩展,当学会了数字板设计之后,就可以尝试着提出一些可靠性较高的数字系统解决方案,这时候基本就具备项目经理的素质了。学会射频板,不妨可以扩展的学习设计微带微波滤波器或者腔体滤波器,一些常用天线,这些当然不是主业的,但是起码要做到了解。要不别人说天线增益和方向性系数,自己不知道啥意思。说滤波器的Q值对滤波器的影响,自己不知道啥意思,这就不太好了。鄙人做过一段时间硬件,认识浅薄,还望大家多多指点。
硬件电路设计需要哪些知识
硬件设计-射频电路设计基础-射频器件基础知识,总共有14课时,本节是第1课时-射频终端链路(1),主讲焦留彦老师,焦留彦老师为EDA365射频、微波论坛特邀版主,原华为射频功放技术专家。课程亮点:射频基本电路以NB-IOT为例,解读3GPP协议关键射频(NB-IOT)指标,理解器件关键指标,掌握选型技能,简要介绍射频指标测试方案;结合硬件工程师的实际工作,让硬件工程师对射频器件有个初步的了解。
怎样破坏电脑硬件
对于一个经常写程序的人来说,写驱动不是一件困难的事情。因为网络上有很多现成的
代码,要实现某个功能,直接 Ctrl+C和Ctrl+V就能解决问题。但是写出来了驱动能不能加
载进入内核就是另外一回事了,准确的说是能不能存在于别人的硬盘上就是另外一回事了。
因为很多杀毒软件(特别像360这种没技术含量的)见到后缀名为sys的文件就直接删除,
甚至连调用NtLoadDriver的机会都没有。对于一般的软件来说,给出一个声明说明一下解
决方法就算了。但是对于恶意程序,是不能给出声明的。于是很多恶意软件的作者另辟蹊径,
利用大*写好的而且有数字签名的驱动来做坏事。
有人说,大*做好的驱动怎么可能被用来做坏事呢?其实,这是很容易理解的事情。
很多安全类或者系统优化类的软件,甚至系统毫不相关的软件(比如:迅雷)都附带有驱动。
这些驱动都带有一定的通用性。q_lai_a_qu网友在其博客里说:“ComputerZ.sys……没事
逆了逆是鲁大师的驱动,发现这个驱动功能齐全,而且没有调用者验证!既可以读、写Msr
寄存器,也可以用in、out指令读写端口,而且char/short/long数据长度齐全!”。这个是
个人之言,可信度请自行揣度。下面说个可信度比较高的例子:曾经有病毒利用了360的
AntiRK.dll来删除杀毒软件的文件(请自行用谷歌搜索“360 antirk.dll”,会有惊喜发现。
AntiRK.dll虽然不是驱动,但也是被非法利用了)。破坏杀毒软件的病毒已经算是小儿科了,
其实利用某些驱动还能破坏硬件!我最近在笔记本上折腾硬件,“本友会”上的网友给我推
荐了几款软件:SetFSB、ThrottleStop、NvFlash、WinFlash。它们分别是修改CPU外频、设
置CPU倍频(可以调节CPU电压)、读写显卡BIOS和读写主板BIOS的软件。一言概括他们的特性,
就是它们都支持NT x86/x64,它们的驱动都有正规数字签名(特别是最后两个,分别带的是 NVIDIA和ASUS的数字签名)。
最为重要的是,他们的驱动没有加花加壳,没有校验调用者,
如果利用这几个驱动,加上一丁点的逆向知识,就能做出破坏性的病毒(以下摘自我在紫水
晶编程论坛的帖子):
1.SetFSB能调节处理器的外频,如果直接把外频调到600MHz,电脑会瞬间黑屏,可能
会损坏 CPU或主板;
2.ThrottleStop能调节 CPU的倍频(如果CPU没有锁倍频),如果直接把倍频调到 31,
电脑会瞬间黑屏,可能会损坏CPU或主板;ThrottleStop还能调节CPU的核心电压,如果
把CPU的核心电压调到3V,能直接烧毁CPU甚至主板;
3.NvFlash、WinFlash等软件能直接读写BIOS(显卡BIOS和主板BIOS),我们可以把
BIOS全部写零;
4.如果做病毒的话,先写坏显卡BIOS和主板BIOS,然后通过调节电压烧掉显卡和CPU
(有可能会连同主板一起损坏);
解决方案
由此可见,没有验证调用者的驱动实在是有着巨大的危害。我最近受学院委托,做一个
需要驱动的软件(那个驱动会被加上数字签名)。为了防止上述悲剧发生,我决定在正式写
驱动之前,先解决如何防止自己的驱动被恶意利用。以前我曾经在紫水晶编程论坛上问过这
个问题,网友的回答五花八门,不过大概是可以分成三类:第一类是信息验证,比如应用程
序发个信息给驱动来验证一下是“自己人”;第二类是加壳保护,比如给驱动和应用程序加
上极强难脱的壳,利用VMP加密通信部分(类似XueTr的做法);还有人提出混合应用,综
合第一类和第二类的做法。
这三种想法看似都不错,但是我认为不妥。第一种:别人只要把驱动全部逆向完毕就行
了;第二种:虽然VMP保护和加保护壳使得*不容易,但是不是使*变得不可能。而且
VMP和保护壳能使程序执行的效率降低,我不太喜欢。最可恶的是,杀毒软件对加了壳(甚
至包括 UPX)和 VMP的程序一律报毒,得不偿失。于是我想出了第三种思路:校验调用者的
特征。如果符合,就执行功能语句,否则不予执行。如何校验调用者的特征码呢?不少人想
到的是使用CRC32或者 MD5。使用它们不是不可以,不过我还有自己的想法。我的想法是自
己设计一套验证算法,它的规则如下:
1.获得调用者的EPROCESS
2.通过调用者的EPROCESS获得调用者的文件路径
3.获取调用者的文件全部内容,放到字节数组buff里
4.把 buff里所有的元素依次相加减(fb1+ fb2- fb3…),得到y1
5.把 buff里所有的元素依次异或(0 XOR fb1 XOR fb2 XOR fb3…),得到y2
把 y1和 y2与已经计算出来的数值对比,如果都相同则执行功能代码,如果不相同则不
执行功能代码
获得调用者的EPROCESS直接用 PsGetCurrentProcess()就行了,获得调用者的文件路
径比较麻烦,大家可以使用我以前向高手购买的代码(已经封装为函数,方便调用):
//依据 EPROCESS得到进程全路径
VOID GetFullPathByEprocess( ULONG eprocess, PCHAR ProcessImageName)
{
ULONG object;
PFILE_OBJECT FileObject;
UNICODE_STRING FilePath;
UNICODE_STRING DosName;
STRING AnsiString;
FileObject= NULL;
FilePath.Buffer= NULL;
FilePath.Length= 0;
*ProcessImageName= 0;
//Eprocess->sectionobject(offset_SectionObject)
if(MmIsAddressValid((PULONG)(eprocess+offset_SectionObject)))
{
object=(*(PULONG)(eprocess+offset_SectionObject));
//KdPrint((“[GetProcessFileName] sectionobject:0x%x\n”,object));
if(MmIsAddressValid((PULONG)((ULONG)object+0x014)))
{
object=*(PULONG)((ULONG)object+0x014);
//KdPrint((“[GetProcessFileName] Segment:0x%x\n”,object));
if(MmIsAddressValid((PULONG)((ULONG)object+0x0)))
{
object=*(PULONG)((ULONG_PTR)object+0x0);
//KdPrint((“[GetProcessFileName]
ControlAera:0x%x\n”,object));
if(MmIsAddressValid((PULONG)((ULONG)object+0x024)))
{
object=*(PULONG)((ULONG)object+0x024);
if(NtBuildNumber>= 6000) object=((ULONG)object&
0xfffffff8);
//KdPrint((“[GetProcessFileName]
FilePointer:0x%x\n”,object));
}
else
return;
}
else
return;
}
else
return;
}
else
return;
FileObject=(PFILE_OBJECT)object;
FilePath.Buffer= ExAllocatePool(PagedPool,0x200);
FilePath.MaximumLength= 0x200;
//KdPrint((“[GetProcessFileName]
FilePointer:%wZ\n”,&FilePointer->FileName));
ObReferenceObjectByPointer((PVOID)FileObject,0,NULL,KernelMode);
RtlVolumeDeviceToDosName(FileObject-> DeviceObject,&DosName);
RtlCopyUnicodeString(&FilePath,&DosName);
RtlAppendUnicodeStringToString(&FilePath,&FileObject->FileName);
ObDereferenceObject(FileObject);
RtlUnicodeStringToAnsiString(&AnsiString,&FilePath, TRUE);
if( AnsiString.Length>= 216)
{
memcpy(ProcessImageName, AnsiString.Buffer, 0x100u);
*(ProcessImageName+ 215)= 0;
}
else
{
memcpy(ProcessImageName, AnsiString.Buffer, AnsiString.Length);
ProcessImageName[AnsiString.Length]= 0;
}
RtlFreeAnsiString(&AnsiString);
ExFreePool(DosName.Buffer);
ExFreePool(FilePath.Buffer);
}
以上代码需要三个硬编码,分别是NtBuildNumber(系统版本号)、EPROCESS中的
SectionObject项和UniqueProcessId项的偏移。我测试的*作系统是Windows 2003。所以
我在代码里如下定义:
#define offset_SectionObject 0x124
#define offset_UniqueProcessId 0x94
ULONG NtBuildNumber=3790;
获得进程路径后就校验特征码。由于流程已经说清楚了,所以直接给出代码:
VOID CalcChar(PUNICODE_STRING logFileUnicodeString, LONG*XorChar, LONG
*AnSChar)
{
OBJECT_ATTRIBUTES objectAttributes;
IO_STATUS_BLOCK iostatus;
HANDLE hfile;
NTSTATUS ntStatus;
FILE_STANDARD_INFORMATION fsi;
PUCHAR pBuffer;
ULONG i=0,y1=0,y2=0;
//初始化 objectAttributes
InitializeObjectAttributes(&objectAttributes,
logFileUnicodeString,
OBJ_CASE_INSENSITIVE,//对大小写敏感
NULL,
NULL);
//创建文件
ntStatus= ZwCreateFile(&hfile,
GENERIC_READ,
&objectAttributes,
&iostatus,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ,
FILE_OPEN,//即使存在该文件,也创建
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0);
if(!NT_SUCCESS(ntStatus))
{
dprintf(“The file is not exist!\n”);
return;
}
//读取文件长度
ntStatus= ZwQueryInformationFile(hfile,
&iostatus,
&fsi,
sizeof(FILE_STANDARD_INFORMATION),
FileStandardInformation);
dprintf(“The program want to read%d bytes\n”,fsi.EndOfFile.QuadPart);
//为读取的文件分配缓冲区
pBuffer=(PUCHAR)ExAllocatePool(PagedPool,
(LONG)fsi.EndOfFile.QuadPart);
//读取文件
ZwReadFile(hfile,NULL,
NULL,NULL,
&iostatus,
pBuffer,
(LONG)fsi.EndOfFile.QuadPart,
NULL,NULL);
dprintf(“The program really read%d bytes\n”,iostatus.Information);
//异或计算
for(i=0;i<iostatus.Information;i++)
y1=y1^(LONG)(*(pBuffer+i));
*XorChar=y1;
//加减计算
for(i=0;i<iostatus.Information;i++)
{
if(i%2==0)
y2=y2+(LONG)(*(pBuffer+i));
else
y2=y2-(LONG)(*(pBuffer+i));
}
*AnSChar=y2;
//关闭文件句柄
ZwClose(hfile);
//释放缓冲区
ExFreePool(pBuffer);
}
接下来就要调用了。我们需要编写一个函数VerifyCaller,在此函数里有两个值需要
固化在驱动里,就是合法调用者的两个特征值。为了方便计算这两个特征值,我特地写了个
应用程序,核心代码如下:
Option Explicit
Private Function ReadFile(ByVal strFileName As String, Optional ByVal
lngStartPos As Long= 1, Optional ByVallngFileSize As Long=-1) As Byte()
Dim FilNum As Long
FilNum= FreeFile
Open strFileName For Binary As#FilNum
If lngFileSize=-1 Then
ReDim ReadFile(LOF(FilNum)- lngStartPos)
Else
ReDim ReadFile(lngFileSize- 1)
End If
Get#FilNum, lngStartPos, ReadFile
Close#FilNum
End Function
Private Function WriteFile(ByVal strFileName As String, bytData() As Byte,
Optional ByVal lngStartPos As Long=-1,Optional ByVal OverWrite As Boolean=
True)
On Error GoTo erx
Dim FilNum As Long
FilNum= FreeFile
If OverWrite= True And Dir(strFileName)<>”” Then
Kill strFileName
End If
Open strFileName For Binary As#FilNum
If lngStartPos=-1 Then
Put#FilNum, LOF(FilNum)+ 1, bytData
Else
Put#FilNum, lngStartPos, bytData
End If
Close#FilNum
erx:
End Function
Private Sub Command1_Click()
Dim buff() As Byte, i As Long, y As Long, ub As Long
'text1.text is the file name
buff= ReadFile(Text1.Text, 1,-1)
ub= UBound(buff)
'calc xor char
y= 0
For i= 0 To ub
y= y Xor buff(i)
Next
Text2.Text= CLng(y)
DoEvents
'calc add/sub char
y= 0
For i= 0 To ub
If i Mod 2= 0 Then
y= y+ CLng(buff(i))
Else
y= y- CLng(buff(i))
End If
Next
Text3.Text= CLng(y)
End Sub
Private Sub Form_Load()
Me.Icon= LoadPicture(“”)
End Sub
驱动里的 VerifyCaller代码如下:
LONG VerifyCaller(void)
{
PEPROCESS cur_ep;
char cur_pp[260];
char*nt_cur_pp;
ANSI_STRING asCur_pp;
UNICODE_STRING usCur_pp;
LONG xorc, ansc;
cur_ep=PsGetCurrentProcess();
GetFullPathByEprocess((ULONG)cur_ep, cur_pp);
//在文件名前面加上\??\
nt_cur_pp=cs(“\\??\\”,cur_pp);
DbgPrint(“%s”,nt_cur_pp);
RtlInitAnsiString(&asCur_pp, nt_cur_pp);
RtlAnsiStringToUnicodeString(&usCur_pp,&asCur_pp, TRUE);
DbgPrint(“%wZ”,&usCur_pp);
CalcChar(&usCur_pp,&xorc,&ansc);
DbgPrint(“XorChar:%ld; AnSChar:%ld”,xorc,ansc);
//这个就是事先算好的合法程序的特征码,【必须】固化在驱动里!
if(xorc==186&& ansc==136176)
return 1;
else
return 0;
}
在 DispatchIoctl函数的每个功能执行之前,都调用VerifyCaller()校验一下调用者:
switch(uIoControlCode)
{
case IOCTL_VERIFY:
{
DbgPrint(“[MyDriver] DispatchIoctl- IOCTL_VERIFY”);
if(VerifyCaller()==1)
DbgPrint(“[MyDriver]{IOCTL_VERIFY} Function code run now!”);
else
DbgPrint(“[MyDriver]{IOCTL_VERIFY} You're illegal caller!”);
status= STATUS_SUCCESS;
break;
}
//下面省略
}
运行测试
3.首先把合法的调用者,非法的调用者(用eXeScope随便把合法的调用者Patch一下,
比如删掉程序的版本信息)和驱动复制到虚拟机
4.用合法的调用者来加载驱动并执行
5.用非法的调用者来加载驱动并执行
6.对比以上两者在DbgView的输出
调用者合法时:
调用者非法时:
写在最后
写完这篇文章,我必须再次重申:只有当驱动程序携带正式数字签名时,验证调用者的
代码才有使用价值。为什么这么说呢?因为别人无法patch带有正式数字签名的驱动(一旦
驱动被 patch,签名就失效了,就像被破处的女人,不值钱了。这个比喻虽然粗俗,但是很
恰当)。而没有加上签名的驱动,本来就没有使用价值。即使别人要使用,直接把驱动扔到
IDA里,什么代码都出来了。
本文链接:http://www.ahdhgm.com/html/87966037.html
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件举报,一经查实,本站将立刻删除。