下载
加入VIP
  • 专属下载特权
  • 现金文档折扣购买
  • VIP免费专区
  • 千万文档免费下载

上传资料

关闭

关闭

关闭

封号提示

内容

首页 实用电脑技术实例-0592

实用电脑技术实例-0592.PDF

实用电脑技术实例-0592

等你来聊
2012-06-20 0人阅读 举报 0 0 暂无简介

简介:本文档为《实用电脑技术实例-0592pdf》,可适用于高等教育领域

破解技术实例【学习逆向工程分析机器代码】(一)标题:【学习逆向工程分析机器代码】(一)作者:sertty详细信息:、序由于最近对逆向工程产生了浓厚的兴趣所以就利用UltraEdit撰写了一个麻雀虽小但五脏俱全的“testc”程序。然后用OD对它进行逆向工程逐步分析机器代码。主要目的是:探索CC编译器是如何产生机器代码及验证CRT函数及带参数的自定义函数的call对栈产生的影响push和pop对栈具体的实现分析for结构和if结构及while产生的机器代码。为此我分别生成了一个优化版本及另一个未经优化版本。、一个具体而微的C程序包括以下内容:)主函数main:主函数main内有一个变量及一些CRT函数的调用和一个if结构)函数mystrcmp:它是一个字节串比较的自定义函数。函数有两个参数:一个源字节串另一个目标字节串并且函数体内则有三个变量另外在程序结构上有一个for循环及if结构。源程序如下:#include<windowsh>#include<stdioh>#include<conioh>#include<ctypeh>intmain(){charbufferprintf("请输入序列号:n")scanf("s",buffer)if(mystrcmp(buffer,"SN")==)printf("注册成功!n")elseprintf("注册失败!n")getche()return}为了测试代码并没有优化并且还特意使用了三个局部变量intmystrcmp(constchar*pszSrc,constchar*pszDest){char*pSrc=(char*)pszSrcchar*pDest=(char*)pszDestintiResult=for(*pSrc!=*pDest!=pSrc,pDest){iResult=*pSrc*pDestif(iResult!=)returniResult}return}、编译在XPSP环境下开一个cmdexe键入VC进入我们的textc目录键入b完成未优化版本编译。键入bopt完成优化版本编译。以下是vcbat和bbat及boptbat的批处理内容:VCbatechooffsetVCDIR=I:ProgramFilesMicrosoftVisualStudioVCsetinclude=I:DXSDKIncludeVCDIRIncludeVCDIRatlincludeVCDIRmfcincludesetlib=I:DXSDKLibVCDIRlibVCDIRmfclibsetpath=c:I:ProgramFilesMicrosoftVisualStudioCommonMSDevBinVCDIRBinsetVCDIR=echoonbbatclexecGztestclinkexesubsystem:consoletestoptobjLIBCLIBkernellibboptbatclexecGzOFotestoptobjtestclinkexesubsystem:consoleOUT:testoptexetestoptobjLIBCLIBkernellib、逆向过程打开OllyDBG加载testoptexe然后在地址设置断点。按下F后我们来到断点处接着便是F一路逐行分析代码:〖O优化版本〗主函数:intmain()imgae地址机器代码汇编代码注释$ECsubesp,charbufferesp|CpushCpush"请输入序列号:n"esp|EAAcall<printf>callprintfD|Dleaeax,dwordptrespleaeax,buffer获取buffer的指针|pusheaxpushbufferesp|pushpush"s"esp|Ecall<scanf>callscanfC|CCaddesp,Cesp释放刚刚函数的参数调用的个push堆栈平衡。此时esp的值又指向buffer了F|DCleaecx,dwordptrespleaeax,buffer获取buffer的指针。|pushpush"SN"传入我们的序列号,esp|pushecxpushbufferesp|Ecall<mystrcmp>调用自定义函数比较字节串。注意!自定义的函数在执行完后会执行retn<stackusedbytes>释放参数栈。而CRT的则不会。call指令内部实现:esp,<mystrcmp>然后在那函数内的retn也会释放这个esp占用的字节。E|Ctesteax,eax测试结果|jnzshortA如果刚刚键入的序列号和系统的不配备就跳到“注册失败”|CpushCpush"注册成功!n"esp|EBcall<printf>callprintfC|Caddesp,释放printf参数调用占用的stack堆栈平衡F|EDcall<getche>callgetche|Cxoreax,eax执行return清空返回值EAX|Caddesp,释放buffer|Cretn结束main函数A|>pushpush"注册失败!n"espF|Ecall<printf>callprintf|Caddesp,释放printf参数调用占用的stack堆栈平衡|Ecall<getche>callgetcheC|Cxoreax,eax执行return清空返回值EAXE|Caddesp,释放bufferCretn结束main函数自定义函数:intmystrcmp(constchar*pszSrc,constchar*pszDest)imgae地址机器代码汇编代码注释>$BCmovecx,dwordptresp获取参数pszSrc。由于CPU执行了call指令esp目前指向本函数地址esp则指向第一个参数pszSrc压参数时是由右至左所以则是指最后入栈的参数|pushesi备份esi寄存器esp|cmpbyteptrecx,判断pszSrc指向的第一个字符是否为|Fjeshort如果为就退出函数A|BCmovesi,dwordptrespC获取第二个参数指针pszDest。因为esp是esi的备份soE|BFsubesi,ecxpszDest=pszSrc得到一个pszDest的偏移从而让下一条指令的esiecx完成索引pszDest串操作|>AEmovdl,byteptresiecxfor结构。获取pszDest指向的字符到dl中|D|testdl,dl测试*pszDest==||jeshort如果为就退出函数。表示已到pszDest串尾|FBE|movsxeax,byteptrecx获取pszSrc指向的当前字符到eax中A|FBED|movsxedx,dl获取pszDest指向的当前字符到edx中D|BC|subeax,edxiResult=*pSrc*pDest。O优化的结果。优化为这三条F|A|jnzshortBif(iResult!=)returniResult|A|moval,byteptrecxal=*(pszSrc)下一个pszSrc指向的字符||incecxpszSrcpszSrc指针|C|testal,al测试是否为|^Ejnzshort如果不为表示还未到串尾继续进行下一轮比较|>Cxoreax,eax返回表示相等和strcmp一样B|>Epopesi恢复esiCCretn执行retn<stackusedbytes>释放参数栈(pszSrc和pszDest)〖未经优化版本〗主函数:intmain()imgae地址机器代码汇编代码注释$pushebpbackupebp|BECmovebp,espbackupesp|ECsubesp,charbuffer|pushASCII"请输入序列号:n"BECBcall<printf>|Caddesp,|DCleaeax,dwordptrebp|pusheax|pushASCII"s"C|EAcall<scanf>callscanf|Caddesp,|pushArg=ASCII"SN"|DDCleaecx,dwordptrebp|C|pushecx|Arg=bufferD|EBcall<mystrcmp>callmystrcmp|Ctesteax,eax|Fjnzshort|pushASCII"注册成功!n"B|EBcall<printf>|Caddesp,|EBDjmpshort|>pushASCII"注册失败!n"A|ECcall<printf>F|Caddesp,|>EAcall<getche>|Cxoreax,eax|BEmovesp,ebpresumeespB|DpopebpresumeebpCCretn自定义函数:intmystrcmp(constchar*pszSrc,constchar*pszDest)imgae地址机器代码汇编代码注释D>$pushebpbackupebpcallparmscurrent=*=D=HE|BECmovebp,espbackupesp|ECCsubesp,C定义三个变量=D=CH|Bmoveax,dwordptrebpchar*pSrc=(char*)pszSrcebp=pushebp,ebp=call,ebp=lastpushparam|FmovdwordptrebpC,eax|BDCmovecx,dwordptrebpCchar*pDest=(char*)pszDestC|DFmovdwordptrebp,ecxF|CFC>movdwordptrebp,intiResult=|EBjmpshortA|>BFmovedx,dwordptrebpCedx=pSrcB|C|addedx,pSrcE|F|movdwordptrebpC,edx|BF|moveax,dwordptrebpeax=pDest|C|addeax,pDest|F|movdwordptrebp,eaxA|>BDFmovecx,dwordptrebpC*pSrc!=D|FBE|movsxedx,byteptrecx|D|testedx,edx测试是否到串尾||jeshortBC如果是就退出函数|BF|moveax,dwordptrebp*pDest!=|FBE|movsxecx,byteptreaxA|C|testecx,ecx测试是否到串尾C|E|jeshortBC如果是就退出函数E|BF|movedx,dwordptrebpC将pSrc指向的字符赋给EDXA|FBE|movsxeax,byteptredx将pSrc指向的字符赋给EAXA|BDF|movecx,dwordptrebp将pDest指针赋给ECXA|FBE|movsxedx,byteptrecx将pDest指向的字符赋给EDXAA|BC|subeax,edxiResult=*pSrc*pDestAC|FC|movdwordptrebp,eaxAF|DFC|cmpdwordptrebp,if(iResult!=)B||jeshortBA如果==就继续比较下一字符B|BFC|moveax,dwordptrebp否则就returniResultB|EB|jmpshortBE否则就returniResultBA|>^EBBCjmpshort继续比较下一字符BC|>Cxoreax,eaxBE|>BEmovesp,ebpresumeespC|DpopebpresumeebpCCretn执行retn<stackusedbytes>释放参数栈(pszSrc和pszDest)由上面的代码可看出:)由于在编译时我给clexe添加了优化选项O(大写字母o和阿拉伯数字)这个选项将会尽最大程度的优化PE的执行速度。所以这机器代码看起来和C的源程序不太像(具体参照mystrcmp内C程序的实现及未经优化版本的反汇编代码))if和while及for:根据它们条件的复杂度相应的编译成适合地跳转指令)全局变量:被统一放在PE的data区。在需要使用的代码处都是以地址操作的)局部变量和参数:都是放在栈中。一般以esp来操作由于栈是向下伸长的所以每增加一个参数的传递(push操作)或是增加局部变量都是以“subesp,<N>”完成的而它的释放则是“addesp,<N>”。另外在跟踪的过程中我发现CPU在执行call指令时是先esp存<funcnextaddr>入栈再jmp<funcaddr>的当执行函数的retn指令时便回收esp出栈<funcnextaddr>继续执行下一条指令。虽然这个过程中我们在代码中看不见不过这些具体的操作是由call及retn内部实现的。另外push、pop指令都是一样的成对操作!从而完成堆栈平衡的机制。^^、总结在跟踪代码的过程中明白了之前看别人反汇编代码郁闷的几个地方。那就是一般CRT函数在进行call之后编译器不会主动地在CRT函数内帮你释放参数占用的栈而是在call之后主动插上一条“addesp,<参数占用的栈数量以机器字为单位>”来维持堆栈平衡。在自定义的函数中我们则无须担心这个问题。编译器会在return处释放参数占用的栈(retn<N>)。像这种东西只有真正分析过机器代码才知道的。另外在未经优化的版本中所产生的机器代码几乎和C源程序一模一样。并且在每个函数的实现细节几乎如下:开头必有:pushebpmovebp,esp结尾必有:movesp,ebppopebp由此大家都可见未经优化的版本内的局部变量及参数不是直接用esp而是ebp!分析完整个流程后那个心情呀可真舒畅!

用户评价(0)

关闭

新课改视野下建构高中语文教学实验成果报告(32KB)

抱歉,积分不足下载失败,请稍后再试!

提示

试读已结束,如需要继续阅读或者下载,敬请购买!

文档小程序码

使用微信“扫一扫”扫码寻找文档

1

打开微信

2

扫描小程序码

3

发布寻找信息

4

等待寻找结果

我知道了
评分:

/11

实用电脑技术实例-0592

VIP

在线
客服

免费
邮箱

爱问共享资料服务号

扫描关注领取更多福利