【文章标题】: MFC的逆向工程 - 给SPYXX.exe添加新功能
【文章作者】: Suyana
【作者邮箱】: Suyasha@163.com
【作者QQ号】: 517949855(请注明来自看雪论坛)
【软件名称】: VC++6.0自带(SPYXX.exe)
【编写语言】: VC++,MFC
【使用工具】: OllyDBG,ResHacker
【操作平台】: WinXP
【软件介绍】: VC++6.0自带的工具
【作者声明】: 本文原创于Suyana, 转载请注明作者并保持文章的完整, 谢谢!
------------------------------------------------------------------------------------
【详细过程】
  1.用VC++6.0或ResHacker修改程序资源(对话框->200),添加四个按钮。偶的四个按钮的ID是1000,1002,1003,1004。程序界面比较挤,偶把它汉化后修改了大小,重新调整位置。如图1

  2.分析一下,实现这四个功能需要两条函数:EnableWindow、ShowWindow。程序里都有,就不用手工添加了,还要获得要操作的窗口的句柄。用资源修改器查看一下程序显示窗口句柄的控件的ID是201(0c9h),所以在OD中"查找"->"所有命令",输入"push 0c9"。来到:

代码:

          0042BC88        mov     edx, [edi+220]          ; 这里保存的就是目标窗口的句柄因地址是变化的,所以要保存起来
          0042BC8E        push    edx                           ; 修改成jmp 0044B0B8
          0042BC8F        call    00427810
          0042BC94        add     esp, 4
          0042BC97        mov     ecx, esi
          0042BC99        push    eax
          0042BC9A        push    0C9
          0042BC9F        call    <jmp.&MFC42.#5953_CWnd::SetDlgItemTex>
  在0044B0B8处添加偶门的代码:
          0044B0B8        mov     [46CFF0], edx           ; 保存到这个地方
          0044B0BE        push    edx                           ; 被覆盖的代码
          0044B0BF        call    00427810                    ; 被覆盖的代码
          0044B0C4        jmp     0042BC94                 ; 继续执行

  3.MFC工程中要到消息的处理过程是很麻烦的,有兴趣的话去一下看雪吧,那里有讲。偶是替换转到
    mfc42.dll的跳转实现的。
      方法A:用MFC SPY找到OnCommand的地址。偶也不懂怎么说,看图2

      方法B:用OllyDbg,用导入库处理,重新载入,这样mfc函数名才会显示出来。随便找到1个mfc
            函数,按回车,就来到末尾一大片jmp ....的地方,找到OnCommand
    按上面的方法,偶找到的是:
    00447F0A        jmp     [<&MFC42.#4441_CWnd::OnCommand>]      ;MFC42.#4441_CWnd::OnCommand
    在程序末尾找到空白的地方0044B03E,把上面代码改成jmp 0044B03E
    CWnd::OnCommand只有一个参数,就是控件的ID,只要判断是不是偶的按钮的ID就可以了
  4.在0044B03E处添加偶门的代码:
代码:

          0044B03E        push    ebp
          0044B03F        mov     ebp, esp
          0044B041        pushad
          0044B042        mov     eax, [ebp+8]            ; 取第一个参数
          0044B045        cmp     eax, 3E8                   ; 是不是ID=1000的按钮Enable
          0044B04A        jnz     short 0044B054
          0044B04C        push    1                              ; 可用
          0044B04E        pop     ebx
          0044B04F        call    0044B090                   ; 为了省代码,偶写了一个函数,用来使窗口可用或禁用,ebx=1为可用,0为禁用
          0044B054        cmp     eax, 3EA                   ; 是不是ID=1002的按钮Disable
          0044B059        jnz     short 0044B063
          0044B05B        push    0                              ; 禁用
          0044B05D        pop     ebx
          0044B05E        call    0044B090
          0044B063        cmp     eax, 3EB                   ; 是不是ID=1003的按钮Show
          0044B068        jnz     short 0044B072
          0044B06A        push    5                              ; 显示
          0044B06C        pop     ebx
          0044B06D        call    0044B0A3                  ; 自己写的函数,用来显示或隐藏窗口
          0044B072        cmp     eax, 3EC                  ; 是不是ID=1004的按钮Hide
          0044B077        jnz     short 0044B081
          0044B079        push    0                             ; 隐藏
          0044B07B        pop     ebx
          0044B07C        call    0044B0A3
          0044B081        popad
          0044B082        nop
          0044B083        pop     ebp
          0044B084        jmp     [44C664]                 ; 跳到MFC42库的OnCommand

  在0044B090写入偶的第一个函数:
代码:

          0044B090        push    ebx                         ; /Enable
          0044B091        mov     eax, [46CFF0]         ; |
          0044B096        push    eax                         ; |hWnd => NULL
          0044B097        call    [44C9AC]                  ; \EnableWindow
          0044B09D        retn                                   ; 返回

  在0044B0A3写入偶的第二个函数:
代码:

          0044B0A3        push    ebx              ; /ShowState
          0044B0A4        mov     eax, [46CFF0]         ; |
          0044B0A9        push    eax                         ; |hWnd => NULL
          0044B0AA        call    [44C8F0]                   ; \ShowWindow
          0044B0B0        retn

  保存就可以了,试一下,是不是可以把窗口隐藏、显示、禁用、使之可用了呢!

--------------------------------------------------------------------------------
【经验总结】
  主要是MFC的消息处理,有很多种方法。可以看《看雪论坛精华》,我这种方法应该算是比较简单(偷懒??)的方法... T_T
  
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!
------------------------------------------------------------------
文章写于2007-08-05