返回列表 发帖

[转帖]失业的娱乐-IDA逆向工程入门(三)-汇编程序(2)

作者:layper 【文章标题】: 失业的娱乐-IDA逆向工程入门(三)-汇编程序(2) 【文章作者】: layper 【作者邮箱】: layper@yahoo.comcn 【作者主页】: http://blog.csdn.net/layper/ 【下载地址】: 自己搜索下载 【编写语言】: asm 【使用工具】: IDA\reshack\radasm\ 【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教! -------------------------------------------------------------------------------- 【详细过程】 多谢大家的支持,特别是fly还关心我的工作问题,无已回报,只能继续写些小文供大家批评了!!! 上一篇我们所逆的是非常简单的win32汇编,总共才两个api函数,一个消息框和ExitProcess函数,这篇我们就涉及一个真正的窗口 程序firstwindows,我学汇编是看了罗云彬的《windows环境下汇编语言程序设计》才入门的,我直接拿里面的例子来讲吧,如果作 者觉得不合适,我会删去的!!!!! 顺便讲一下学习逆向工程的方法,这个跟学脱壳方法类似,你先用一种语言写一个程序(刚开始比较简单的),编译后用IDA或者 其他工具反汇编,观察源代码和反汇编代码有什么异同,想办法在逆向代码中逐渐靠近源代码,最后再把他整理到编译工具中不 断编译,在编译器中看那里出错,逐步修改,直至成功,最后总结经验,这样就会逐步提高了. 限于篇幅,我只把完整源码贴出来,未修改的反汇编在压缩包内的1.asm,请自行查看 firstwindows源码 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ; Sample code for < Win32ASM Programming > ; by 罗云彬, http://asm.yeah.net ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ; FirstWindow.asm ; 窗口程序的模板代码 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ; 使用 nmake 或下列命令进行编译和链接: ; ml /c /coff FirstWindow.asm ; Link /subsystem:windows FirstWindow.obj ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> .386 .model flat,stdcall option casemap:none ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ; Include 文件定义 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> include windows.inc include gdi32.inc includelib gdi32.lib include user32.inc includelib user32.lib include kernel32.inc includelib kernel32.lib ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ; 数据段 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> .data? hInstance dd ? hWinMain dd ? .const szClassName db ';MyClass';,0 szCaptionMain db ';My first Window !';,0 szText db ';Win32 Assembly, Simple and powerful !';,0 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ; 代码段 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> .code ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ; 窗口过程 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> _ProcWinMain proc uses ebx edi esi,hWnd,uMsg,wParam,lParam local @stPsAINTSTRUCT local @stRect:RECT local @hDc mov eax,uMsg ;******************************************************************** .if eax == WM_PAINT invoke BeginPaint,hWnd,addr @stPs mov @hDc,eax invoke GetClientRect,hWnd,addr @stRect invoke DrawText,@hDc,addr szText,-1,\ addr @stRect,\ DT_SINGLELINE or DT_CENTER or DT_VCENTER invoke EndPaint,hWnd,addr @stPs ;******************************************************************** .elseif eax == WM_CLOSE invoke DestroyWindow,hWinMain invoke PostQuitMessage,NULL ;******************************************************************** .else invoke DefWindowProc,hWnd,uMsg,wParam,lParam ret .endif ;******************************************************************** xor eax,eax ret _ProcWinMain endp ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> _WinMain proc local @stWndClass:WNDCLASSEX local @stMsg:MSG invoke GetModuleHandle,NULL mov hInstance,eax invoke RtlZeroMemory,addr @stWndClass,sizeof @stWndClass ;******************************************************************** ; 注册窗口类 ;******************************************************************** invoke LoadCursor,0,IDC_ARROW mov @stWndClass.hCursor,eax push hInstance pop @stWndClass.hInstance mov @stWndClass.cbSize,sizeof WNDCLASSEX mov @stWndClass.style,CS_HREDRAW or CS_VREDRAW mov @stWndClass.lpfnWndProc,offset _ProcWinMain mov @stWndClass.hbrBackground,COLOR_WINDOW + 1 mov @stWndClass.lpszClassName,offset szClassName invoke RegisterClassEx,addr @stWndClass ;******************************************************************** ; 建立并显示窗口 ;******************************************************************** invoke CreateWindowEx,WS_EX_CLIENTEDGE,offset szClassName,offset szCaptionMain,\ WS_OVERLAPPEDWINDOW,\ 100,100,600,400,\ NULL,NULL,hInstance,NULL mov hWinMain,eax invoke ShowWindow,hWinMain,SW_SHOWNORMAL invoke UpdateWindow,hWinMain ;******************************************************************** ; 消息循环 ;******************************************************************** .while TRUE invoke GetMessage,addr @stMsg,NULL,0,0 .break .if eax == 0 invoke TranslateMessage,addr @stMsg invoke DispatchMessage,addr @stMsg .endw ret _WinMain endp ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> start: call _WinMain invoke ExitProcess,NULL ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> end start 在radasm编译通过. 用IAD反汇编载入完成后,点击文件-创建文件-创建asm文件就得到未经修改的反汇编后得到的1.asm文件(有点绕口),直接用 radasm打开,在radasm中ctrl+f5构建并运行看看结果怎样,呵呵,出错了. 因为一步一步来讲比较长,我先把操作过程写下来,在慢慢解释,1.asm修改如下: (一)增加模式定义\options语句\还原include语句 .686p .mmx .model flat,stdcall option casemap:none include WINDOWS.INC include kernel32.inc includelib kernel32.lib include user32.inc includelib user32.lib (二)删除结构MSG\POINT\PAINTSTRUCT\RECT,并把余下的结构移动到 includelib user32.lib之后,即第一步之后, 然后做如下修改: tagMSG struc ; (sizeof=0x1C, standard type) hwnd dd ? ; offset message dd ? wParam dd ? lParam dd ? time dd ? pt POINT ? ;这里修改为pt POINT <> tagMSG ends tagPAINTSTRUCT struc ; (sizeof=0x40, standard type) hdc dd ? ; offset fErase dd ? rcPaint RECT ? ;这里修改为rcPaint RECT <> fRestore dd ? fIncUpdate dd ? rgbReserved db 32 dup(?) tagPAINTSTRUCT ends (三)对函数的局部变量进行修改 一共三个函数start\sub_401000和sub_401089,修改如下 sub_401089: sub_401089 proc near ; CODE XREF: startp Msg = MSG ptr -4Ch var_30 = WNDCLASSEXA ptr -30h 修改为: sub_401089 proc near ; CODE XREF: startp LOCAL Msg:MSG LOCAL var_30:WNDCLASSEXA sub_401000: sub_401000 proc near ; DATA XREF: sub_401089+43o hDC = dword ptr -54h Rect = tagRECT ptr -50h Paint = PAINTSTRUCT ptr -40h hWnd = dword ptr 8 Msg = dword ptr 0Ch wParam = dword ptr 10h lParam = dword ptr 14h 修改为: sub_401000 proc uses ebx edi esi ,hWnd,Msg,wParam,lParam ; DATA XREF: sub_401089+43o LOCAL hDC LOCAL Rect:tagRECT LOCAL PaintAINTSTRUCT (四)_text段修改 删除 在_text段前增加.code _text segment para public ';CODE'; use32 assume cs:_text ;org 401000h assume es:nothing, ss:nothing, ds:_data, fs:nothing, gs:nothing 和 _text ends 注意:中间的代码不要删除!!! (五)删除align 40h (六)移动修改_data段 在.code前增加.data,并且把_data段移动到这里 把 _data segment para public ';DATA'; use32 assume cs:_data ;org 403000h 和 ; sub_401089+A6r _data ends 删除 注意:中间的代码不要删除!!! (七)修改sub_401000的hWnd,只要出现有的都修改为hWnd1. (八)删除_idata段 (九) 把函数含有[ebp+变量]的代码全部修改为变量 sub_401089的代码 [ebp+var_30] 改为 var_30 [ebp+var_30.hCursor] 改为 var_30.hCursor [ebp+var_30.hInstance] 改为 var_30.hInstance [ebp+var_30.cbSize] 改为 var_30.cbSize [ebp+var_30.style] 改为 var_30.style [ebp+var_30.lpfnWndProc] 改为 var_30.lpfnWndProc [ebp+var_30.hbrBackground] 改为 var_30.hbrBackground [ebp+var_30.lpszClassName] 改为 var_30.lpszClassName [ebp+Msg] 改为 Msg sub_401000的代码 [ebp+hDC] 改为 hDC [ebp+Rect] 改为 Rect [ebp+Paint] 改为 Paint [ebp+hWnd1] 改为 hWnd1 [ebp+Msg] 改为 Msg [ebp+wParam] 改为 wParam [ebp+lParam] 改为 lParam (十)删掉函数多余的开头 sub_401089处: sub_401089 proc near ; CODE XREF: startp LOCAL Msg:MSG LOCAL var_30:WNDCLASSEXA push ebp ;删掉 mov ebp, esp 删掉 add esp, 0FFFFFFB4h ;删掉 sub_401000处: sub_401000 proc near uses ebx edi esi ,hWnd1,Msg,wParam,lParam ; DATA XREF: sub_401089+43o LOCAL hDC LOCAL Rect:tagRECT LOCAL PaintAINTSTRUCT push ebp ;删掉 mov ebp, esp ;删掉 add esp, 0FFFFFFACh ;删掉 push ebx ;删掉 push edi ;删掉 push esi ;删掉 -------------------------------------------------------------------------------- 【经验总结】 其实只要你把反编译的代码按照radasm的提示一步一步修改就可以了. 解释: (一) 这一步我在上篇已经解释的比较明白了.因为我们汇编开头就是那么几句代码. include语句加回去这个是因为我们编译的是汇编程序,这样肯定要用到库.如果IDA使用生成的_data段 就非常容易出错.毕竟它只是"识别"而不是源码!!!!!!! (二) (1)删除结构体MSG\POINT\PAINTSTRUCT\RECT 我们进行了第一步操作后,用radasm进行构建,就会提示我们 D:\masm32\Include\WINDOWS.INC(7873) : error A2163: : POINT D:\masm32\Include\WINDOWS.INC(7874) : error A2163: : POINT D:\masm32\Include\WINDOWS.INC(8841) : error A2163: : MSG D:\masm32\Include\WINDOWS.INC(8842) : error A2163: : MSG D:\masm32\Include\WINDOWS.INC(8843) : error A2163: : MSG D:\masm32\Include\WINDOWS.INC(8844) : error A2163: : MSG D:\masm32\Include\WINDOWS.INC(8845) : error A2163: : MSG D:\masm32\Include\WINDOWS.INC(8846) : error A2163: : MSG D:\masm32\Include\WINDOWS.INC(8846) : fatal error A1016: 构建时发生错误. 总共编译时间 271 毫秒 这个这个意思说我们的库文件出错,这个可能吗?当然也有可能,但我想你首先应该想到是你的反汇编代码错. 先查询一下windows.inc"出错"的到底是什么 POINT STRUCT x DWORD ? ;7873行 y DWORD ? ;7874行 POINT ENDS MSG STRUCT hwnd DWORD ? ;8841 message DWORD ? ;8842 wParam DWORD ? ;8843 lParam DWORD ? ;8844 time DWORD ? ;8845 pt POINT <> ;8846 MSG ENDS 呵呵,你再看看反汇编代码开头 MSG struc ; (sizeof=0x1C, standard type) hwnd dd ? ; offset message dd ? wParam dd ? lParam dd ? time dd ? pt POINT ? MSG ends ; --------------------------------------------------------------------------- POINT struc ; (sizeof=0x8, standard type) x dd ? y dd ? POINT ends 明白怎么是这样了吧?我们反汇编代码重复定义了结构msg,point所以要把他们删除.同理PAINTSTRUCT\RECT也删除了. (2)移动剩余结构到include语句后. 这一步我是为了省事,剩余三个结构 tagMSG struc ; (sizeof=0x1C, standard type) hwnd dd ? ; offset message dd ? wParam dd ? lParam dd ? time dd ? pt POINT ? tagMSG ends ; --------------------------------------------------------------------------- WNDCLASSEXA struc ; (sizeof=0x30, standard type) cbSize dd ? style dd ? lpfnWndProc dd ? ; offset cbClsExtra dd ? cbWndExtra dd ? hInstance dd ? ; offset hIcon dd ? ; offset hCursor dd ? ; offset hbrBackground dd ? ; offset lpszMenuName dd ? ; offset lpszClassName dd ? ; offset hIconSm dd ? ; offset WNDCLASSEXA ends ; --------------------------------------------------------------------------- tagRECT struc ; (sizeof=0x10, standard type) left dd ? top dd ? right dd ? bottom dd ? tagRECT ends ; --------------------------------------------------------------------------- tagPAINTSTRUCT struc ; (sizeof=0x40, standard type) hdc dd ? ; offset fErase dd ? rcPaint RECT ? fRestore dd ? fIncUpdate dd ? rgbReserved db 32 dup(?) tagPAINTSTRUCT ends 其中tagMSG和tagPAINTSTRUCT结构分别用到了POINT结构和RECT结构,刚才我们删了,只有windows.inc中有 所以直接把他们剪切到这里省去出错的机会. (3)修改结构 tagMSG结构和tagPAINTSTRUCT结构修改,我是参照windows.inc结构定义方法.结构中用结构<> 这个不一定完全正确,想研究这方面多阅读.inc文件 (三)函数修改 在反汇编代码中只要出现proc的,到现在为止我都看成是函数!!! IDA反汇编都它的函数都变成这个样子 sub_401000 proc near ; DATA XREF: sub_401089+43o hDC = dword ptr -54h ;注意这里是减(-) Rect = tagRECT ptr -50h Paint = PAINTSTRUCT ptr -40h hWnd = dword ptr 8 ;这里其实是加(+) Msg = dword ptr 0Ch wParam = dword ptr 10h lParam = dword ptr 14h push ebp mov ebp, esp add esp, 0FFFFFFACh push ebx push edi push esi mov eax, [ebp+Msg] 这里就会出现一个问题.我们先前又删结构又改结构,而这里又用到结构,不修改编译也会出错的. 我们改成比较正规的win32汇编程序格式. 刚才我提示加减的地方,总结一条规律给大家: 函数开头 xx = 结构 - xxh 这个就是函数的局部变量,可用local xx:结构替换. 函数开头 xx = dword ptr xxh 这个是函数的参数,函数可改为 函数名 proc xx (四)_text段修改 代码段 _text segment para public ';CODE'; use32 assume cs:_text ;org 401000h assume es:nothing, ss:nothing, ds:_data, fs:nothing, gs:nothing 和 _text ends IDA这种段写法有很大的弊端,也是引起我们修改后的代码编译不通过的一个很重要原因.(具体我还说不上来,我还很菜) (五)删除align 40h align是反汇编代码不通过编译的一种常见错误. (六)移动修改_data段 一般来说_data段是我们的数据段,一般我们放在前面.(呵呵,代码顺序也很重要) (七)在数据段中 hWnd dd ? ; DATA XREF: sub_401000+54r ; sub_401089+94w sub_401089+9Br ; sub_401089+A6r 提示hWnd是函数sub_401089的,并不是sub_401000,所以要重命名他们. (八)删除_idata段 include语句已经有了函数定义,再保留这里就会出错. (九) 把函数含有[ebp+变量]的代码全部修改为变量 [ebp+]这个是编译器加上去的,我们直接用的话,编译后会变成[ebp+ebp+变量],容易出错. (十)删掉函数多余的开头 反汇编代码中,编译器为你加上象这样的代码 push ebp mov ebp, esp add esp, 0FFFFFFB4h 如果你直接编译的话代码就变成了: push ebp mov ebp, esp add esp, 0FFFFFFB4h push ebp mov ebp, esp add esp, 0FFFFFFB4h 重新编译也容易出错,所以要删去. 同理,要注意函数结束地方看看是否要删去. (十一) 这里说一点跟上一篇不同的是没有删除_rdata,因为这里有我们程序要的数据,所以没删除.如 果你还想优化自己弄了!!! 呵呵,终于弄完这篇了,把它整理好花了好大工夫.错误难免,请多包涵!!!! -------------------------------------------------------------------------------- 【版权声明】: 本文原创于UnPacKcN论坛, 转载请注明作者并保持文章的完整, 谢谢!

返回列表 回复 发帖