【文章标题】: 失业的娱乐-IDA逆向工程入门(四)-汇编程序实战
【文章作者】: layper
【作者邮箱】:
layper@yahoo.com.cn【作者主页】:
http://blog.csdn.net/layper/【软件名称】: biatch
【下载地址】: 自己搜索下载
【使用工具】: IDA,Radasm,Resource Hacker
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
这段时间忙着学习网页制作,刚刚初学,N多问题要学习,搞得我头晕脑涨.现在放松一下,继续逆向玩玩.:)
汇编程序在逆向工程中是比较简单的一种语言,反汇编得到的代码基本上与源码差不多,只是稍微作点修改就可以了.前面的
几篇都是有源码对照的例子,这篇我们进行实战,没有源码.:)
这是老外的一个工具biatch,今天拿他开刀.
IDA载入完成后,文件-创建文件-创建asm文件保存为1.asm。接着用Resource Hacker载入biatch,保存对话框资源为1.rc。
用RadASM载入1.asm,好了初步工作完成了,接下来先按照上次我写的第三篇步骤来修改.
(一)增加模式定义\options语句\还原include\lib语句
在IDA中Shift+F7打开区段窗口接着双击.idata来到.idata段,
.idata:00403000 ;
.idata:00403000 ; Imports from comdlg32.dll注意这里,使用comdig32.dll
.idata:00403000 ;
.idata:00403000 ; 屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯?
.idata:00403000
.idata:00403000 ; Segment type: Externs
.idata:00403000 ; _idata
.idata:00403000 ; BOOL __stdcall GetOpenFileNameA(LPOPENFILENAMEA)
.idata:00403000 extrn __imp_GetOpenFileNameA:dword
.idata:00403000 ; DATA XREF: GetOpenFileNameAr
.idata:00403000 ; Create an Open common dialog box
.idata:00403004
.idata:00403008 ;
.idata:00403008 ; Imports from gdi32.dll注意这里,使用gdi32.dll
.idata:00403008 ;
.idata:00403008 ; HFONT __stdcall CreateFontIndirectA(const LOGFONTA *)
.idata:00403008 extrn __imp_CreateFontIndirectA:dword
.idata:00403008 ; DATA XREF: CreateFontIndirectAr
.idata:0040300C ; BOOL __stdcall DeleteObject(HGDIOBJ)
.idata:0040300C extrn __imp_DeleteObject:dword ; DATA XREF: DeleteObjectr
.idata:00403010
.idata:00403014 ;
.idata:00403014 ; Imports from kernel32.dll注意这里,使用kernel32.dll
.idata:00403014 ;
.idata:00403014 ; LPTOP_LEVEL_EXCEPTION_FILTER __stdcall SetUnhandledExceptionFilter(LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter)
.idata:00403014 extrn __imp_SetUnhandledExceptionFilter:dword
.idata:00403014 ; DATA XREF: SetUnhandledExceptionFilterr
.idata:00403018 ; HANDLE GetProcessHeap(void)
.idata:00403018 extrn __imp_GetProcessHeap:dword
.idata:00403018 ; DATA XREF: GetProcessHeapr
.idata:0040301C ; BOOL __stdcall CloseHandle(HANDLE hObject)
.idata:0040301C extrn __imp_CloseHandle:dword ; DATA XREF: CloseHandler
.idata:00403020 ; HANDLE __stdcall CreateFileA(LPCSTR lpFileName,DWORD dwDesiredAccess,DWORD dwShareMode,LPSECURITY_ATTRIBUTES lpSecurityAttributes,DWORD dwCreationDisposition,DWORD dwFlagsAndAttributes,HANDLE hTemplateFile)
.idata:00403020 extrn __imp_CreateFileA:dword ; DATA XREF: CreateFileAr
.......................
........................
.idata:00403040 ; HMODULE __stdcall GetModuleHandleA(LPCSTR lpModuleName)
.idata:00403040 extrn __imp_GetModuleHandleA:dword
.idata:00403040 ; DATA XREF: GetModuleHandleAr
.idata:00403044 ; void __stdcall ExitProcess(UINT uExitCode)
.idata:00403044 extrn __imp_ExitProcess:dword ; DATA XREF: ExitProcessr
.idata:00403048 ; LPVOID __stdcall HeapAlloc(HANDLE hHeap,DWORD dwFlags,DWORD dwBytes)
.idata:00403048 extrn __imp_HeapAlloc:dword ; DATA XREF: HeapAllocr
.idata:0040304C
.idata:00403050 ;
.idata:00403050 ; Imports from user32.dll注意这里,使用user32.dll
.idata:00403050 ;
.idata:00403050 ; LONG __stdcall SetWindowLongA(HWND hWnd,int nIndex,LONG dwNewLong)
.idata:00403050 extrn __imp_SetWindowLongA:dword
.idata:00403050 ; DATA XREF: SetWindowLongAr
.................................
.idata:00403098 extrn __imp_CheckDlgButton:dword
.idata:00403098 ; DATA XREF: CheckDlgButtonr
.idata:00403098 ; Change the check state of a button control
.idata:0040309C ; LRESULT __stdcall CallWindowProcA(WNDPROC lpPrevWndFunc,HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam)
.idata:0040309C extrn __imp_CallWindowProcA:dword
.idata:0040309C ; DATA XREF: CallWindowProcAr
.idata:004030A0 ; BOOL __stdcall ShowWindow(HWND hWnd,int nCmdShow)
.idata:004030A0 extrn __imp_ShowWindow:dword ; DATA XREF: ShowWindowr
.idata:004030A4 ; int wsprintfA(LPSTR,LPCSTR,...)
.idata:004030A4 extrn __imp_wsprintfA:dword ; DATA XREF: wsprintfAr
.idata:004030A8
从这里知道了用到四个dll,即comdlg32.dll、gdi32.dll、kernel32.dll、user32.dll,所以我们还原的include和includelib就要包含
这几个dll。
所以把
.686p
.mmx
.model flat
还原成:
.686p
.mmx
.model flat,stdcall
option casemap:none
include WINDOWS.INC
include comdlg32.inc
includelib comdlg32.lib
include gdi32.inc
includelib gdi32.lib
include kernel32.inc
includelib kernel32.lib
include user32.inc
includelib user32.lib
删除前面的.idata段.
(二)删除结构
在RadASM中Ctrl+F5试着构建并运行,有错误提示.
D:\masm32\Include\WINDOWS.INC(9666) : error A2163: : LOGFONTA
D:\masm32\Include\WINDOWS.INC(9667) : error A2163: : LOGFONTA
D:\masm32\Include\WINDOWS.INC(9668) : error A2163: : LOGFONTA
D:\masm32\Include\WINDOWS.INC(9669) : error A2163: : LOGFONTA
D:\masm32\Include\WINDOWS.INC(9670) : error A2163: : LOGFONTA
从这里可以判断1.asm的LOGFONTA导致出错,删除LOGFONTA结构(在开头处).把tagOFNA结构移动到includelib user32.lib后面.
(三)修改移动_data段
在_text段前增加
.data
把_data全部移到.data之后
删除_data段开头的
_data segment para public 'DATA' use32
assume cs:_data
和_data末尾的
_data ends
注意:中间的代码不要删除!!!
(四)修改_text段
加上.code
_text segment para public 'CODE' use32 ;在这之前加上.code
删除_text开头的
_text segment para public 'CODE' use32
assume cs:_text
;org 401000h
assume es:nothing, ss:nothing, ds:_data, fs:nothing, gs:nothing
和_text末尾的
_text ends
注意:中间的代码不要删除!!!
(五)修改hWnd错误
在RadASM中Ctrl+F5试着构建并运行,有错误提示.
D:\crack\国外工具\tf10\1.asm(834) : error A2005: : hWnd
D:\crack\国外工具\tf10\1.asm(1286) : error A2005: : hWnd
D:\crack\国外工具\tf10\1.asm(1499) : error A2005: : hWnd
D:\crack\国外工具\tf10\1.asm(1640) : error A2005: : hWnd
D:\crack\国外工具\tf10\1.asm(2609) : error A2189: : 128
D:\crack\国外工具\tf10\1.asm(821) : error A2005: : hWnd
D:\crack\国外工具\tf10\1.asm(1277) : error A2005: : hWnd
D:\crack\国外工具\tf10\1.asm(1489) : error A2005: : hWnd
D:\crack\国外工具\tf10\1.asm(1629) : error A2005: : hWnd
在.data段寻找hWnd
; HWND hWnd
hWnd dd 0 ; DATA XREF: DialogFunc+241r
; DialogFunc+264w DialogFunc+26Dr
; DialogFunc+28Br DialogFunc+29Dr
; sub_401500+9r ...
这个提示两个函数DialogFunc和sub_401500用到这个全局变量hWnd,其他函数的hWnd错误的地方。我们
逐条寻找出错位置
1.asm(834) : error A2005: : hWnd
这条错误在
sub_401500 proc near ; CODE XREF: DialogFunc+21Fp
var_18 = dword ptr -18h
var_14 = dword ptr -14h
var_10 = dword ptr -10h
var_C = dword ptr -0Ch
hWnd = dword ptr -8 ;这里出错,这里的局部变量hWnd与全局变量hWnd冲突,修改为hWnd1
lpMem = dword ptr -4
hDlg = dword ptr 8
在IDA中打开Functions窗口,找到sub_401500,
sub_401500 .text 00401500 00000291 R . . . B T .
双击来到sub_401500处
.text:00401500 sub_401500 proc near ; CODE XREF: DialogFunc+21Fp
.text:00401500
.text:00401500 var_18 = dword ptr -18h
.text:00401500 var_14 = dword ptr -14h
.text:00401500 var_10 = dword ptr -10h
.text:00401500 var_C = dword ptr -0Ch
.text:00401500 hWnd = dword ptr -8 ;修改这里为hWnd1
.text:00401500 lpMem = dword ptr -4
.text:00401500 hDlg = dword ptr 8
在hWnd上右键-重命名把hWnd为hWnd1.
注意:推荐在IDA里面重命名hWnd,经过修改后IDA自动识别全局变量hWnd和hWnd1比手动快,而且正确率高.
继续查找
1.asm(1286) : error A2005: : hWnd
错误在
sub_401810 proc near ; CODE XREF: sub_401380+130p
hWnd = dword ptr -8 ;在IDA中修改为hWnd1
lpMem = dword ptr -4
hDlg = dword ptr 8
1.asm(1499) : error A2005: : hWnd
找到
sub_401A10 proc near ; CODE XREF: DialogFunc+233p
var_8 = dword ptr -8
hWnd = dword ptr -4 ;在IDA中修改为hWnd1
hDlg = dword ptr 8
1.asm(1640) : error A2005: : hWnd
找到
sub_401B6C proc near ; DATA XREF: DialogFunc+9Eo
; DialogFunc+CBo sub_401380+57o
hWnd = dword ptr 8 ;这个不是局部变量了
Msg = dword ptr 0Ch
wParam = dword ptr 10h
lParam = dword ptr 14h
因为这里不是局部变量了,我们先修改前面三个函数(或者子程序),sub_401500,sub_401810,sub_401A10.
保存修改后的代码为2.asm,接着把1.asm里的sub_401500,sub_401810,sub_401A10这三个函数全部用2.asm
里的sub_401500,sub_401810,sub_401A10替换掉.
接着在RadASM中Ctrl+F5构建并运行,
D:\crack\国外工具\tf10\1.asm(1640) : error A2005: : hWnd
D:\crack\国外工具\tf10\1.asm(2609) : error A2189: : 128
D:\crack\国外工具\tf10\1.asm(1629) : error A2005: : hWnd
看来sub_401B6C的hWnd也要改掉,在IDA中修改后覆盖到1.asm里,
D:\crack\国外工具\tf10\1.asm(2609) : error A2189: : 128
hWnd没有出现错误了.
(五)删除align
1.asm(2609) : error A2189: : 128 ;这里就是align,直接删除了
(六)修改fs[0]
前面几篇都没有涉及到这个内容,这里就出现关于fs[0]的出错代码的修改.
D:\crack\国外工具\tf10\1.asm(1950) : error A2206:
D:\crack\国外工具\tf10\1.asm(1951) : error A2206:
D:\crack\国外工具\tf10\1.asm(1971) : error A2206:
这几行在1.asm对应的代码是sub_401D80中
push large dword ptr fs:0
mov large fs:0, esp
pop large dword ptr fs:0
这几行代码都在
D:\crack\国外工具\tf10\1.asm(2010) : error A2206:
D:\crack\国外工具\tf10\1.asm(2011) : error A2206:
D:\crack\国外工具\tf10\1.asm(2054) : error A2206:
这几行在1.asm对应的代码是sub_401DE0中
push large dword ptr fs:0
mov large fs:0, esp
pop large dword ptr fs:0
D:\crack\国外工具\tf10\1.asm(2422) : error A2206:
D:\crack\国外工具\tf10\1.asm(2423) : error A2206:
D:\crack\国外工具\tf10\1.asm(2478) : error A2206:
这几行在1.asm对应的代码是sub_402050中
push large dword ptr fs:0
mov large fs:0, esp
pop large dword ptr fs:0
D:\crack\国外工具\tf10\1.asm(2536) : error A2206:
D:\crack\国外工具\tf10\1.asm(2537) : error A2206:
D:\crack\国外工具\tf10\1.asm(2581) : error A2206:
这几行在1.asm对应的代码是sub_4020F0中
push large dword ptr fs:0
mov large fs:0, esp
pop large dword ptr fs:0
这几句代码的写法不正确,我们把他们改为
push fs:[0]
mov fs:[0], esp
pop fs:[0]
试构建运行看看
D:\crack\国外工具\tf10\1.asm(1950) : error A2108:
D:\crack\国外工具\tf10\1.asm(1951) : error A2108:
D:\crack\国外工具\tf10\1.asm(1971) : error A2108:
D:\crack\国外工具\tf10\1.asm(2010) : error A2108:
D:\crack\国外工具\tf10\1.asm(2011) : error A2108:
D:\crack\国外工具\tf10\1.asm(2054) : error A2108:
D:\crack\国外工具\tf10\1.asm(2422) : error A2108:
D:\crack\国外工具\tf10\1.asm(2423) : error A2108:
D:\crack\国外工具\tf10\1.asm(2478) : error A2108:
D:\crack\国外工具\tf10\1.asm(2536) : error A2108:
D:\crack\国外工具\tf10\1.asm(2537) : error A2108:
D:\crack\国外工具\tf10\1.asm(2581) : error A2108:
还是提示出错,经过认真观察,参考了其他代码,我在函数sub_401D80,sub_401DE0,sub_4020F0,sub_4020F0开头处加上一句
代码:
assume fs:nothing
查一下资料,因为MASM编译器默认是把FS定义为error,所以在程序中要使用FS寄存器就要用
assume fs:nothing 来声明,否则就会报错。
构建运行
D:\masm32\BIN\ML.EXE /c /coff /Cp /nologo /I"D:\masm32\Include" "D:\crack\国外工具\tf10\1.asm"
Assembling: D:\crack\国外工具\tf10\1.asm
D:\masm32\BIN\LINK.EXE /SUBSYSTEM:WINDOWS /RELEASE /VERSION:4.0 /LIBPATH:"D:\masm32\LIB" "D:\crack\国外工具\tf10\1.obj"
Microsoft (R) Incremental Linker Version 5.12.8078
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.
执行:
"D:\crack\国外工具\tf10\1.exe"
构建完成.
总共编译时间 781 毫秒
无错误提示,呵呵,我们逆向的代码初步成功了.
(七)加入资源
我们试运行1.exe发现没有出现界面,这个就是没有把资源加回去才出现这种错误的.
利用Resource Hacker生成的1.rc修改后用makefile文件把资源文件编译进去.
1.rc所做的修改如下:
增加
#include <resource.h>
删除掉
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
makefile文件:
NAME = 1
OBJS = $(NAME).obj
RES = $(NAME).res
LINK_FLAG = /subsystem:windows
ML_FLAG = /c /coff
$(NAME).exe: $(OBJS) $(RES)
Link $(LINK_FLAG) $(OBJS) $(RES)
.asm.obj:
ml $(ML_FLAG) $<
.rc.res:
rc $<
clean:
del *.obj
del *.res
注意:这里编译我直接用命令行形式编译,不用RadASM.
呵呵,现在你已经拥有一份不太完善的biatch的源码了.
汇编程序的逆向工程就告一段落了.我这里演示的只是一部分还原方法或注意事项,在实际应用当中
并不是仅仅这几步内容(比如优化就是非常重要),这个就要多多进行练习来提高水平了。
--------------------------------------------------------------------------------
【版权声明】: 转载请注明作者并保持文章的完整, 谢谢!
2007年03月30日 0:46:41