首页
社区
课程
招聘
[旧帖] [求助]学习API HOOK 的问题 0.00雪花
发表于: 2008-3-23 22:02 5553

[旧帖] [求助]学习API HOOK 的问题 0.00雪花

2008-3-23 22:02
5553
今天在学习用 SEH 技术实现 API Hook
源代码在这里http://www.luocong.com/articles/zipped/SEH_APIHook.zip

为了方便,我把源代码贴出来,我抓破脑袋都想不通~

;*********************************************************
;程序名称:用 SEH 技术实现 API Hook
;适用系统:Win NT/2000/XP
;作者:罗聪
;日期:2002-11-22
;出处:http://www.LuoCong.com(老罗的缤纷天地)
;注意事项:如欲转载,请保持本程序的完整,并注明:
;转载自“老罗的缤纷天地”(http://www.LuoCong.com)
;*********************************************************

.386
.model flat, stdcall
option casemap:none

include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\user32.inc
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\user32.lib

WndProc         proto :DWORD, :DWORD, :DWORD, :DWORD
Error_Handler   proto :DWORD, :DWORD, :DWORD, :DWORD
SetHook         proto

.const
IDI_LC                  equ 1
IDC_CHECKBUTTON_HOOK    equ 3000
IDC_BUTTON_ABOUT        equ 3001
IDC_BUTTON_EXIT         equ 3002

.data
szDlgName               db  "lc_dialog", 0
szMsgAbout              db  "-= SEH for API Hook =-", 13, 10, 13, 10,\
                            "作者:罗聪(lcother@163.net)", 13, 10, 13, 10,\
                            "老罗的缤纷天地", 13, 10,\
                            "http://www.LuoCong.com", 13, 10, 0
szMyText                db  13, 10, 13, 10, "(哈哈,看到有什么不同了吗?)", 0
szMsgHooked             db  "MessageBoxIndirectA() has been hooked!",\
                            13, 10, 13, 10,\
                            "即将改变原来的 MessageBoxIndirectA() 的参数,", 13, 10,\
                            "请注意后面的对话框跟没有 Hook 之前有什么不同……", 0
szCaption               db  "SEH for API Hook by LC", 0
szLibUser               db  "user32", 0
szProcMsgBoxInd         db  "MessageBoxIndirectA", 0
dwAddress               dd  0
dwOldProtect            dd  0
bOldByte                db  0
dwRetAddr               dd  0

.data?
hInstance               HINSTANCE       ?
mbp                     MSGBOXPARAMS    <>
szText                  db  1024 dup(?)

.code
main:
    ; 设置 SEH 链:
    assume  fs:nothing
    push    offset Error_Handler
    push    fs:[0]
    mov     fs:[0], esp

    invoke  GetModuleHandle, NULL
    mov     hInstance, eax
    invoke  DialogBoxParam, hInstance, offset szDlgName, 0, WndProc, 0

    ; 恢复原来的 SEH 链:
    pop     fs:[0]
    pop     eax
    invoke  ExitProcess, 0

WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
    .if uMsg == WM_CLOSE
        invoke EndDialog, hWnd, 0

    .elseif uMsg == WM_INITDIALOG
        mov eax, hWnd
        mov [mbp.hwndOwner], eax
        invoke LoadIcon, hInstance, IDI_LC
        invoke SendMessage, hWnd, WM_SETICON, ICON_SMALL, eax
        ; 储存 API 的原入口地址:
        invoke GetModuleHandle, addr szLibUser
        invoke GetProcAddress, eax, addr szProcMsgBoxInd
        mov [dwAddress], eax
        ; 保存原对话框的输出文字:
        invoke lstrcpy, addr szText, addr szMsgAbout

    .elseif uMsg == WM_COMMAND
        mov eax, wParam
        mov edx, eax
        shr edx, 16
        movzx eax, ax
        .if edx == BN_CLICKED
            .if eax == IDC_BUTTON_EXIT || eax == IDCANCEL
                invoke EndDialog, hWnd, NULL

            .elseif eax == IDC_BUTTON_ABOUT || eax == IDOK
                mov [mbp.cbSize], sizeof mbp
                mov eax, hInstance
                mov [mbp.hInstance], eax
                mov [mbp.lpszText], offset szMsgAbout
                mov [mbp.lpszCaption], offset szCaption
                mov [mbp.dwStyle], MB_OK or MB_APPLMODAL or MB_USERICON
                mov [mbp.lpszIcon], IDI_LC
                invoke MessageBoxIndirect, addr mbp

            .elseif eax == IDC_CHECKBUTTON_HOOK
                ; 把内存保护设置成 可读/可写/可执行:
                invoke VirtualProtect, [dwAddress], 1, PAGE_EXECUTE_READWRITE, addr dwOldProtect
                invoke IsDlgButtonChecked, hWnd, IDC_CHECKBUTTON_HOOK
                mov edx, [dwAddress]
                test eax, eax
                .if zero?                                           ; uninstall hook
                    mov cl, [bOldByte]                              ; bOldByte = API 原入口地址
                    mov byte ptr [edx], cl                          ; 恢复 API 的原入口地址
                    invoke lstrcpy, addr szMsgAbout, addr szText    ; 恢复原对话框的输出文字:
                .else                                               ; re-install hook
                    mov cl, byte ptr [edx]                          ; byte ptr [edx] = API 原入口地址
                    mov byte ptr [edx], 0CCh                        ; 断点异常(INT 3 指令)
                    mov [bOldByte], cl                              ; 储存 API 的原入口地址
                    invoke lstrcat, addr szMsgAbout, addr szMyText  ; 改变原对话框的输出文字:
                .endif

            .endif
        .endif
    .else
        mov eax, FALSE
        ret
    .endif
    mov eax, TRUE
    ret
WndProc endp

;****************************************
; 函数功能:处理异常错误
;****************************************
Error_Handler proc uses ecx lpExceptRecord:DWORD, lpFrame:DWORD, lpContext:DWORD, lpDispatch:DWORD
    ; 输出 "API hooked":
    invoke  MessageBox, [mbp.hwndOwner], addr szMsgHooked, addr szCaption,\
            MB_OK or MB_ICONINFORMATION

    ; 储存并改变 SetHook 函数的返回值:(经过修正)
    ; (想不明白?呵呵,用调试器跟踪一下吧,我也说不清楚,只能意会不能言传……)
    mov eax, [lpContext]
    mov eax, [eax][CONTEXT.regEsp]
    mov ecx, [eax]
    mov [eax], offset SetHook
    mov [dwRetAddr], ecx

    ; 把 API 原入口地址写回去,以便继续运行原 API:
    ; (跟踪一下吧,我实在是不知道怎么才能说得清楚……)
    mov eax, [dwAddress]
    mov cl, [bOldByte]
    mov byte ptr [eax], cl

    ; 继续下一个 Execution:
    mov eax, ExceptionContinueExecution
    ret
Error_Handler endp

;****************************************
; 函数功能:设置 API Hook
;****************************************
SetHook proc uses ecx
    mov eax, [dwAddress]
    mov cl, [eax]
    mov byte ptr [eax], 0CCh    ; 断点异常(INT 3 指令)
    mov [bOldByte], cl
    jmp [dwRetAddr]             ; 跳回经过 Hook 之后的 API 的返回地址(很重要!)
SetHook endp

end main
;********************   over    ********************
;by LC


程序很简单,我的问题是这样的:当运行的时候选定“hook MessageBoxIndirect”单选框的时候,以下语句被执行
                .else                                               ; re-install hook
                    mov cl, byte ptr [edx]                          ; byte ptr [edx] = API 原入口地址
                    mov byte ptr [edx], 0CCh                        ; 断点异常(INT 3 指令)
                    mov [bOldByte], cl                              ; 储存 API 的原入口地址
                    invoke lstrcat, addr szMsgAbout, addr szMyText  ; 改变原对话框的输出文字:

此时,dwAddress=0CCh,我的理解是,当选定了“hook MessageBoxIndirect”的时候,变的只有dwAddress,按下关于按钮的时候,触发的是以下语句

            .elseif eax == IDC_BUTTON_ABOUT || eax == IDOK
                mov [mbp.cbSize], sizeof mbp
                mov eax, hInstance
                mov [mbp.hInstance], eax
                mov [mbp.lpszText], offset szMsgAbout
                mov [mbp.lpszCaption], offset szCaption
                mov [mbp.dwStyle], MB_OK or MB_APPLMODAL or MB_USERICON
                mov [mbp.lpszIcon], IDI_LC
                invoke MessageBoxIndirect, addr mbp

但是对话框是如何改变的呢?我觉得SEH根本就没有触发嘛~因为根本没有异常发生~

[课程]Android-CTF解题方法汇总!

收藏
免费 0
支持
分享
最新回复 (16)
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
觉得异常没发生?难不成你是用感觉来判断的?
2008-3-24 00:00
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
msy
3
我顶!
老大们告诉我异常在哪里发生啊~
2008-3-24 12:40
0
雪    币: 206
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
[dwAddress]也就是后来的edx这个地址被写入了0xcc(int3)
所以这里就发生了异常
2008-3-24 13:00
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
msy
5
楼上的意思是说当执行到红色语句的时候

                .else                                               ; re-install hook
                    mov cl, byte ptr [edx]                          ; byte ptr [edx] = API 原入口地址
                    mov byte ptr [edx], 0CCh                        ; 断点异常(INT 3 指令)
                    mov [bOldByte], cl                              ; 储存 API 的原入口地址
                    invoke lstrcat, addr szMsgAbout, addr szMyText  ; 改变原对话框的输出文字:

发生异常,因此没有去执行下一条语句 mov [bOldByte], cl  而跳到Error_Handler proc咯?
2008-3-24 13:12
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
msy
6
看雪的老大们去哪了?我的 问题写得这么详细都没有人来么?
看雪不要让我失望啊~不然会损失老客户的~
2008-3-24 20:18
0
雪    币: 485
活跃值: (12)
能力值: ( LV9,RANK:490 )
在线值:
发帖
回帖
粉丝
7
并不是在那里出现了异常。
此程序是在 API(MessageBoxIndirectA)的入口放入int3(CC)使程序在调用MessageBoxIndirectA时产生单步异常,从而使程序进入我们设计的SEH里来达到HOOK的目的

个人意见,仅供参考。
2008-3-24 20:39
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
msy
8
请问LS,被放入int3的是[dwAddress],但是程序调用的是 invoke MessageBoxIndirect,而不是call dwAddress,那程序如何产生单步异常?
2008-3-24 21:08
0
雪    币: 485
活跃值: (12)
能力值: ( LV9,RANK:490 )
在线值:
发帖
回帖
粉丝
9
invoke GetProcAddress, eax, addr szProcMsgBoxInd
mov [dwAddress], eax
dwAddress 存放的就是 MessageBoxIndirect 的地址
2008-3-24 21:23
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
楼主你应该去掌握的处理器的中断技术,了解什么是中断,发生中断时处理器会干什么就明白了。
2008-3-24 21:25
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
msy
11
(1)有谁可以告诉我这个程序在选定hook message 是程序的流程是什么吗?
(2)SetHook proc uses ecx
    mov eax, [dwAddress]
    mov cl, [eax]
    mov byte ptr [eax], 0CCh    ; 断点异常(INT 3 指令)
    mov [bOldByte], cl
    jmp [dwRetAddr]             ; 跳回经过 Hook 之后的 API 的返回地址(很重要!)
SetHook endp

有人能给我解释一下这段代码的功能吗?
(3)我认为是程序是这样的,首先把MessageBoxIndirectA的代码入口改为INT3,当程序调用MessageBoxIndirectA时发生异常,跳到Error_Handler proc 。
在Error_Handler proc 中,我是这样理解下面代码的。

   mov eax, [lpContext]                 获得各寄存器的值    mov eax, [eax][CONTEXT.regEsp]   将SP的值赋给EAX,其SP指向Error_Handler    proc的返回地址,既代码 .elseif eax == IDC_CHECKBUTTON_HOOK的地址    mov ecx, [eax]     SP有赋给ECX    mov [eax], offset SetHook   将栈顶的返回地址改为SetHook的地址,当执行到ret时跳到SetHook去执行    mov [dwRetAddr], ecx  .elseif eax == IDC_CHECKBUTTON_HOOK的地址保存在dwRetAddr中

所以我的理解的流程是这样的-》执行到MessageBoxIndirectA发生中断-》Error_Handler proc-》SetHook
我的思路到此终止,到了SetHook就不知道它是怎么执行的了
(4)ASM程序不像VC那样可以在源代码中下断点,所以不知道如何调试。有一篇说如何在VC中调试ASM,但是编译时提示 STYLE DS_SETFONT  未定义,不知为何。我包含StdAfx.h文件后不再提示STYLE DS_SETFONT  未定义,但提示unresolved external symbol _mainCRTStartup
2008-3-25 19:35
0
雪    币: 485
活跃值: (12)
能力值: ( LV9,RANK:490 )
在线值:
发帖
回帖
粉丝
12
(1)
  ; 把内存保护设置成 可读/可写/可执行:
  invoke VirtualProtect, [dwAddress], 1, PAGE_EXECUTE_READWRITE, addr dwOldProtect
  invoke IsDlgButtonChecked, hWnd, IDC_CHECKBUTTON_HOOK
  mov edx, [dwAddress]
  test eax, eax
  .if zero?                                           ; uninstall hook
      mov cl, [bOldByte]                              ; bOldByte = API 原入口地址
      mov byte ptr [edx], cl                          ; 恢复 API 的原入口地址
      invoke lstrcpy, addr szMsgAbout, addr szText    ; 恢复原对话框的输出文字:
   .else                                               ; re-install hook
      mov cl, byte ptr [edx]                          ; byte ptr [edx] = API 原入口地址
      mov byte ptr [edx], 0CCh                        ; 断点异常(INT 3 指令)
      mov [bOldByte], cl                              ; 储存 API 的原入口地址
      invoke lstrcat, addr szMsgAbout, addr szMyText  ; 改变原对话框的输出文字:
   .endif

  上面就是程序的流程

 改变API入口地址处的保护属性
 
 IDC_CHECKBUTTON_HOOK Checked?
 
 if not Checked 恢复API入口地址并将显示字符串恢复为存原始字符串
 
 if Checked 将入口首字节改为 CC 并显示字符串改为加入szMyText后的字符串。

(2)&&(3)

 这两个问题要放在一起理解:
  
  mov eax, [lpContext]
  mov eax, [eax][CONTEXT.regEsp]
  mov ecx, [eax]
  mov [eax], offset SetHook
  mov [dwRetAddr], ecx
  
  上面这段代码在做什么呢?我想你能理解,只是你没有放在汇编码的状态下去理解。这段代码其实是在改变异常发生时ESP的值,这个ESP里放的是什么呢?你已经知道了,就是CALL API时push进的返回地址,上面这段代码把这个地址改写成了 SetHook函数的地址,并对原返回地址进行了保存。这样做起到什么作用呢?

 我们此时看下程序流程,假设程序代码如下:
 AAA
 CALL API
 BBB

 我们在Call入API时第一条指令发生了异常(此时堆栈顶为BBB处地址),程序进入异常处理程序。异常处理程序中改变了异常发生时的栈顶内容,即把栈顶的BBB处地址改写成了SetHook的地址,然后把CC改写成了原代码。异常处理完毕后,程序继续到异常发生处执行。当API调用完毕准备返回的时候,因为我们改写了返回地址,所以程序将进入SetHook中执行,我们看SetHook的代码:
  mov eax, [dwAddress]
  mov cl, [eax]
  mov byte ptr [eax], 0CCh    ; 断点异常(INT 3 指令)
  mov [bOldByte], cl
  jmp [dwRetAddr]             ; 跳回经过 Hook 之后的 API 的返回地址(很重要!)
 
 上面很好理解,程序将API入口第一字节再次改为CC,并将程序引导到BBB处。至此,程序在被我们改变了流程之后又进入了原来的轨道。

  好了,现在我们可以站在全局的高度理解下程序流程(我只列出关键部分):

  1 初始化时,获取API的地址和第一字节代码进行保存。
  2 运行后通过判断CheckButton是还先中来设定CC或清除CC
  3 如果已设定CC,点OK CALL API时则进入SEH Handler
    3.1 改变返回地址,恢复原代码
    3.2 API 执行完后,进入SetHook再次恢复CC,并将程序引入原轨道。
  。。。。。。。

  为什么要改变返回地址,最后还又引回原地址,当然是为了设置CC,为了程序完美,你可以试想一下不这样做的结果。

(4)
调试ASM程序用OD,我感觉还是不错的

不知道我说明白了没有,仅供参考吧
2008-3-25 23:03
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
msy
13
谢谢LS大哥的指点,但是还有那么一点小问题

mov [mbp.lpszIcon], IDI_LC
invoke MessageBoxIndirect, addr mbp
.elseif eax == IDC_CHECKBUTTON_HOOK

这3条语句相当与
 AAA
 CALL API
 BBB

首先执行CALL API进入异常后,会执行
invoke  MessageBox, [mbp.hwndOwner], addr szMsgHooked, addr szCaption,\
            MB_OK or MB_ICONINFORMATION
弹出一个提示对话框,异常处理完毕后进入SetHook中,SetHook没有弹出任何东西就跳到
.elseif eax == IDC_CHECKBUTTON_HOOK
去执行了,那么我想问第二个弹出的对话框(既带有“哈哈“字样的对话框)是在哪条语句中执行的?
2008-3-26 07:39
0
雪    币: 485
活跃值: (12)
能力值: ( LV9,RANK:490 )
在线值:
发帖
回帖
粉丝
14
异常处理完毕后程序又从异常发生处恢复执行了,即继续invoke  DialogBoxParam, hInstance, offset szDlgName, 0, WndProc, 0去了,第二个对话框是他.
SetHook不是在异常处理中执行的
2008-3-26 07:51
0
雪    币: 220
活跃值: (28)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
第二个弹出的对话框(既带有“哈哈“字样的对话框)是MessageBoxIndirect执行的
2008-3-26 13:48
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
msy
16
不对吧?在以前的帖子里你不是说异常处理完了就到sethook中吗?怎么会跑到invoke DialogBoxParam, hInstance, offset szDlgName, 0, WndProc, 0那里呢?
2008-3-26 15:07
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
msy
17
我忙了一个下午,终于弄懂了,谢谢ptent大哥!
2008-3-26 16:28
0
游客
登录 | 注册 方可回帖
返回
//