论坛: 编程破解 标题: [转帖]失业的娱乐-IDA逆向工程入门(三)-汇编程序(2) 复制本贴地址    
作者: yongmin [yongmin]    论坛用户   登录
作者: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论坛, 转载请注明作者并保持文章的完整, 谢谢!

地主 发表时间: 07-03-07 11:22

论坛: 编程破解

20CN网络安全小组版权所有
Copyright © 2000-2010 20CN Security Group. All Rights Reserved.
论坛程序编写:NetDemon

粤ICP备05087286号