[原创]IDA对一个简单的键盘钩子逆向分析

您所在的位置:网站首页 keyhook [原创]IDA对一个简单的键盘钩子逆向分析

[原创]IDA对一个简单的键盘钩子逆向分析

2024-07-16 10:33:22| 来源: 网络整理| 查看: 265

文章之前先来个贱卖广告: 文章开始之前,先感谢15PB的老师们之前的辛苦教育。 键盘钩子程序逆向.zip 一、IDA静态逆向分析 (一)、可执行文件流程图 (1)函数1  地址:  main  函数功能:  主函数功能,载入模块,调用模块中的导出功能(挂钩、脱钩) 1)int __cdecl main(int argc, const char **argv, const char **envp) 得出分析结果: ⓐ此函数的返回类型为 int 类型。 ⓑ此函数的调用方式为__cdecl 调用方式,此种调用方式最显著的特点是谁调用此函数谁清栈,所以也可以根据清栈方式判定目标函数是否属于__cdecl调用方式。 push    offset LibFileName ; "Keyhook.dll" call    ds:LoadLibraryA mov     ebx, eax                      call    ds:LoadLibraryA mov     ebx, eax test    ebx, ebx jnz     short loc_401030 得出分析结果: ⓐ调用了LoadLibraryA API函数,且传入的参数是Keyhook.dll。也就是说程序载入Keyhook.dll模块,并判断是否正确载入模块。 反汇编成C: 2)如果1)不执行跳转( ebx = eax = 0)。 push    1               ; uType push    offset Caption  ; "f婮T" push    offset Text     ; "}廵Qd" push    eax             ; hWnd call    ds:MessageBoxW 得出分析结果: ⓐ调用MessageBoxW API函数。 ⓑ窗口句柄:hWnd = eax =0;Text,Caption 参数为乱码,uType = 1。 可以根据上一个判断跳转推断,因为是 ebx = eax = 0 也就是说LoadLibraryA API("Keyhook.dll")载入模块失败,执行的MessageBoxW ,因此这很可能是一个提示载入模块失败的对话框。 1)、2)反汇编成C: if(LoadLibraryA API("Keyhook.dll")) {} MessageBoxW(NULL,L”XXX”,L”YYY”,1); retuen 0; 3)如果1)的判断执行跳转。 mov     esi, ds:GetProcAddress push    edi push    offset ProcName ; "HookStart" push    ebx             ; hModule call    esi ; GetProcAddress push    offset aHookstop ; "HookStop" push    ebx             ; hModule mov     edi, eax         ;HookStart  call    esi ; GetProcAddress mov     [ebp+var_4], eax  ;HookStop  call    edi            ;HookStart  push    offset Format   ; "脱钩请输入 'q'\n" call    ds:printf mov     esi, ds:getchar 得出分析结果: ⓐ调用两次GetProcAddress API函数。 hModule句柄参数是1)LoadLibraryA API("Keyhook.dll")得到的句柄;第二个参数分别是 获取名为: "HookStart","HookStop",也就是获取 Keyhook.dll 模块中名为:"HookStart","HookStop"的两个函数地址,且两个函数都没有使用到返回值,所以可以初步判定两个函数的返回值类型为 void类型。 ⓑ调用printf ,输出"脱钩请输入 'q'\n" 反汇编成C: 因为 GetProcAddress 获取的是一个函数地址,所以最好定义2个函数地址类型变量。 typedef void (*LPFUNCTION_HOOKSTART) (); typedef void (*LPFUNCTION_HOOKSTOP) ();    LPFUNCTION_HOOKSTART HookStart = 0 ; LPFUNCTION_HOOKSTOP HookStop = 0; GetProcAddress(LoadLibraryA ("Keyhook.dll"),”HookStart” ); GetProcAddress(LoadLibraryA ("Keyhook.dll"),”HookStop” ); HookStart(); printf("脱钩请输入 'q'\n"); 4)继续往下执行。 call    esi ; getchar cmp     eax, 71h jnz     short loc_401063 ;call    esi ; getchar 分析得出结果: ⓐ调用getchar ,判断返回值 eax == 71h。getchar 调用的过后面一般会伴随着(do while类型)循环,这里也不例外。 反汇编成C: while(getchar == 71h ) {}; 5)如果getchar == 71h 执行为真。 call    [ebp+var_4]       ;HookStop  push    ebx             ; hLibModule call    ds:FreeLibrary pop     edi pop     esi xor     eax, eax pop     ebx mov     esp, ebp pop     ebp retn 分析得出结果: ⓐ调用 HookStop 函数。 ⓑ调用 FreeLibrary 函数,参数为ebx = LoadLibraryA ("Keyhook.dll")。 4)、5)反汇编成C: while(getchar == 71h ) { HookStop(); FreeLibrary( LoadLibraryA ("Keyhook.dll")); }; return 0; 总结: ⓐ载入Keyhook.dll模块。 ⓑ获取Keyhook.dll模块中的HookStart 函数地址。 ⓒ获取Keyhook.dll模块中的HookStop 函数地址。 ⓓ执行Keyhook.dll模块中的HookStart函数。 ⓔ调用printf("脱钩请输入 'q'\n")。 ⓕ使用while循环,getchar == 71h为判断依据。 ⓖ释放Keyhook.dll模块。 翻译成C++: typedef void (*LPFUNCTION_HOOKSTART) (); typedef void (*LPFUNCTION_HOOKSTOP) ();  int __cdecl main(int argc, const char argv[],) {    if(LoadLibraryA API("Keyhook.dll"))   {        LPFUNCTION_HOOKSTART HookStart = 0 ;        LPFUNCTION_HOOKSTOP HookStop = 0;        GetProcAddress(LoadLibraryA ("Keyhook.dll"),”HookStart” );        GetProcAddress(LoadLibraryA ("Keyhook.dll"),”HookStop” );        HookStart();        printf("脱钩请输入 'q'\n");      while(getchar == 71h )      {       HookStop();       FreeLibrary( LoadLibraryA ("Keyhook.dll"));      };      return 0;    }    MessageBoxW(NULL,L”XXX”,L”YYY”,1);    retuen 0; } 现在需要分析Keyhook.dll模块的HookStart(),HookStop() 两个导出函数的具体功能。(2)函数2地址:  Keyhook.dll.HookStart(),    函数功能:  实现对notepad.exe进程挂钩 因为Keyhook.dll的DllEntryPoint_0没有任何有意义的算法。所以就不分析了,直接分析Keyhook.dll.HookStart()。 从函数头的注释; Exported entry   1. HookStart,可以侧面映证该函数为导出函数。 汇编代码: lea     edi, [ebp+var_C0] mov     ecx, 30h mov     eax, 0CCCCCCCCh rep stosd mov     esi, esp push    0               ; dwThreadId mov     eax, hmod push    eax             ; hmod push    offset fn         ; lpfn push    2               ; idHook call    ds:SetWindowsHookExW cmp     esi, esp call    sub_10011145 mov     esp, ebp 得出分析结果: ⓐ调用 SetWindowsHookExW 函数。参数1(idHook = 2);参数2( lpfn = fn,函数地址,也就是说该值是一个函数的起始地址,稍后再分析);参数3(eax = hmod,hmod的值存放在.data数据段中且hmod = 0,因此可以判断此函数是全局变量或者static 变量);参数4(dwThreadId = 0)。 ⓑsub_10011145的调用只是用于堆栈检查,不去要做详细的分析。但由此函数不需要清栈可以推断,这是stdcall/thiscall中的一个,但HookStart()函数里没有使用到this值,所以可以判断这是stdcall调用方式。 反汇编成C: __std(export) void HookStart() { DWORD idHook = 2; HMODULE hmod = 0; DWORD dwThreadId = 0;     SetWindowHookExW(idHook ,lpfn , hmod,dwThreadId);     return ; } (3)函数3地址:   fn  重命名:  lpfn  函数功能:  对目标进程进行判断(过滤); int __stdcall lpfn(int nCode, WPARAM wParam, LPARAM lParam) 1)汇编代码: mov     eax, ___security_cookie ; eax = ebx xor     eax, ebp mov     [ebp+var_4], eax mov     [ebp+szStr], 0 push    103h            ; Size push    0               ; Val lea     eax, [ebp+szDst] push    eax             ; Dst call    j_memset add     esp, 0Ch mov     [ebp+Dword_1], 0 cmp     [ebp+nCode], 0    jl      short loc_1001145F  得出分析结果: ⓐ调用j_memset 函数初始化一个字符串,目标数据(参数1:szDst),初始值(参数2:Val = 0),长度为(参数3:Size = 103h)。 ⓑ局部变量 Dword_1 =0。 ⓒ判断参数 nCode 是否等于0。 2)、汇编代码: mov     eax, [ebp+lParam] and     eax, 80000000h jnz     short loc_1001145F     得出分析结果: ⓐ参数lParam 与 80000000h 相与,然后进行判断,不等于则跳转。  1)、2)反汇编成C: int __stdcall lpfn(int nCode, WPARAM wParam, LPARAM lParam) { CHAR szDst[103h] ={0,}; DWORD Dword_1 = 0; if( nCode >= 0 ) {     if(lParam & 80000000h)     {              } } } 3)汇编代码: mov     esi, esp push    104h            ; nSize lea     eax, [ebp+szStr] push    eax             ; lpFilename push    0               ; hModule call    ds:GetModuleFileNameA cmp     esi, esp  call    sub_10011145 push    5Ch             ; int lea     eax, [ebp+szStr] push    eax             ; Str call    sub_100110A5 add     esp, 8 得出分析结果: ⓐ调用GetModuleFileNameA ,参数1(hModule = 0 ,默认本模块自身),参数2(lpFilename = szStr =szDst),参数3(nSize = 104h)。 ⓑsub_10011145 函数只是对栈检查而已,无需多虑。 ⓒ调用 sub_100110A5 函数,因为传入了两个参数(Str,5Ch),且不像是系统自调函数,所以需要跟入,稍后跟进分析。 4)汇编代码: mov     [ebp+Dword_1], eax mov     esi, esp push    offset Str2     ; "notepad.exe" mov     eax, [ebp+Dword_1] add     eax, 1 push    eax             ; Str1 call    ds:_stricmp add     esp, 8 cmp     esi, esp call    sub_10011145 test    eax, eax jnz     short loc_1001145F    得出分析结果: ⓐ获取调用sub_100110A5 函数的返回值,传给变量Dword_1 = eax。 ⓑ调用_stricmp 函数,参数1(Dword_1 + 1 == eax+1 ),参数2(Str2 是一个全局变量,Str2 == )。由char Str2[] .rdata:10015658 6E 6F 74 65 70 61 64 2E+Str2            db 'notepad.exe',0 可以判定这是一个CHAR 数组全局/静态变量,但如果是静态变量会在某个函数中出现定义,但却没有,所以可以确定这是一个全局变量。 ⓒsub_10011145没有对eax进行操作,而_stricmp 有返回值(使用到eax),所以test    eax, eax,判定的是_stricmp 的返回值是否为假。 3)、4)反汇编成C: CHAR g_szProcName[] =  "notepad.exe";    //全局变量  HMODULE hModule = NULL; GetModuleFileNameA(hModule,szDst,104h ); Dword_1 = sub_100110A5(szStr,5Ch); if(_stricmp(Dword_1 + 1 ,g_szProcName)) {  } 5)在4)test    eax, eax 结果为0的情况下,执行的汇编代码: mov     eax, 1 jmp     short loc_10011480 ⓐeax +1 ⓑ跳转至loc_10011480 继续执行(后面的是系统自动调用的函数,主要是做栈安全检测),返回eax结果,结束函数调用。 反汇编成C: return 1; 6)汇编代码: mov     esi, esp mov     eax, [ebp+lParam] push    eax             ; lParam mov     ecx, [ebp+wParam] push    ecx             ; wParam mov     edx, [ebp+nCode] push    edx             ; nCode mov     eax, hhk push    eax             ; hhk call    ds:CallNextHookEx cmp     esi, esp 得出分析结果: ⓐ调用CallNextHookEx 函数。参数1(eax = hhk = 0,hhk是一个全局变量),参数2(edx = nCode),参数3(ecx = wParam),参数4(eax = lParam)。 ⓑ再往下是占清理代码和返回CallNextHookEx 的返回值。 反汇编成C: HHOOK g_hhk =0; return CallNextHookEx(g_hhk, nCode,wParam,lParam); 总结: 此函数主要是用于判定目标程序是不是"notepad.exe",如果是就返回CallNextHookEx的返回值,即挂钩,如果不是就返回 1。总而言至就是判断当前扑捉到的是不是"notepad.exe"进程,然后对"notepad.exe"进程挂钩。 翻译成C++: HHOOK g_hhk =0;                       //全局变量 CHAR g_szProcName[] =  "notepad.exe";    //全局变量  int __stdcall fn_0(int nCode, WPARAM wParam, LPARAM lParam) { CHAR szDst[103h] ={0,}; DWORD Dword_1 = 0; if( nCode >= 0 ) {     if(lParam & 80000000h)     {             HMODULE hModule = NULL;             GetModuleFileNameA(hModule,szDst,104h );             Dword_1 = sub_100110A5(szStr,5Ch);             if(_stricmp(Dword_1 + 1 ,g_szProcName == 0))             {                  return 1;             }                 return CallNextHookEx(g_hhk, nCode,wParam,lParam);     } } } (4)函数4地址:  Keyhook.dll.HookStop()        函数功能:  此函数功能只是对以挂钩的进程进行脱钩。 mov     esi, esp mov     eax, hhk push    eax             ; hhk call    ds:UnhookWindowsHookEx cmp     esi, esp call    sub_10011145 mov     hhk, 0 得出分析结果: ⓐ调用UnhookWindowsHookEx进行脱钩,参数(hhk:全局变量) 反汇编成C: ⓑ将全局变量置为 0(hhk= 0). UnhookWindowsHookEx(hhk); hhk= 0; 总结: 此函数主要是进行脱钩。 翻译成C: void  __std(export) HookStop() {     UnhookWindowsHookEx(hhk);     g_hhk= 0;     return 0; } 整合翻译成C: HHOOK g_hhk =0;                       //全局变量 CHAR g_szProcName[] =  "notepad.exe";    //全局变量  BOOL __stdcall DllEntryPoint(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved) { return TRUE; } __std(export) void HookStart() { DWORD idHook = 2; HMODULE hmod = 0; DWORD dwThreadId = 0;     SetWindowHookExW(idHook ,lpfn , hmod,dwThreadId);     return ; } int __stdcall lpfn (int nCode, WPARAM wParam, LPARAM lParam) { CHAR szDst[0x103] ={0,}; DWORD Dword_1 = 0; if( nCode >= 0 ) {     if(lParam & 80000000h)     {             HMODULE hModule = NULL;             GetModuleFileNameA(hModule,szDst,0x104 );             Dword_1 = sub_100110A5(szStr,0x5C);             if(_stricmp(Dword_1 + 1 ,g_szProcName == 0))             {                  return 1;             }                 return CallNextHookEx(g_hhk, nCode,wParam,lParam);     } } } void __std(export)  HookStop() {     UnhookWindowsHookEx(g_hhk);     g_hhk= 0;     return 0; }            文章结束!应该会有勘误,望指出。  谢谢大神的赏脸! 淘气鬼(放牛娃)

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件: 键盘钩子程序逆向.zip (37.79kb,20次下载) 图片1.png (6.99kb,8次下载)


【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


图片新闻

实验室药品柜的特性有哪些
实验室药品柜是实验室家具的重要组成部分之一,主要
小学科学实验中有哪些教学
计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
实验室各种仪器原理动图讲
1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
高中化学常见仪器及实验装
1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
微生物操作主要设备和器具
今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
浅谈通风柜使用基本常识
 众所周知,通风柜功能中最主要的就是排气功能。在

专题文章

    CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭