加密与解密二版菜鸟学习笔记-Anti-spy,加密与解密,反跟踪技术 2008年06月23日 星期一 下午 02:15 【文章标题】 菜鸟《加密与解密》二版学习笔记(1)-反调试,及OD中API断点的使用 【软件名称】Anti-spy.exe 【下载地址】《加密与解密》二版配套光盘 【使用工具】flyod 1.10 【保护方式】Anti-SPY : regmon filemon 【开发语言】MasM 【本文写于】2005-2-1 【软件简介】《加密与解密》二版,第10章反Anti练习程序。 ————————————————————————————————— 【破解分析】 破解分析 1.-------------------------------------------------------------------------------------------- Od载入,来到入口代码: 00401000 A>/$Content$nbsp; 6A 01 push 1 00401002 |. 6A 00 push 0 00401004 |. 6A 00 push 0 00401006 |. 6A 00 push 0 ; /pModule = NULL 00401008 |. FF15 00204000 call dword ptr ds:[<&KERNEL32.GetModuleHandle>; \GetModuleHandleA 0040100E |. 50 push eax 0040100F |. E8 0C000000 call Anti-Spy.00401020 //应用程序入口 『 00401020 /$Content$nbsp; 8B4424 04 mov eax,dword ptr ss:[esp 4] ; Anti-Spy.00400000 00401024 |. 6A 00 push 0 ; /lParam = NULL 00401026 |. 68 A0104000 push Anti-Spy.004010A0 ; |DlgProc = Anti-Spy.004010A0 0040102B |. 6A 00 push 0 ; |hOwner = NULL 0040102D |. 6A 65 push 65 ; |pTemplate = 65 0040102F |. 50 push eax ; |hInst 00401030 |. A3 08314000 mov dword ptr ds:[403108],eax ; 00401035 |. FF15 20204000 call dword ptr ds:[<&USER32.DialogBoxParamA>] ; \DialogBoxParamA //产生对话 0040103B |. 33C0 xor eax,eax 0040103D \. C2 1000 retn 10 』 00401014 |. 50 push eax ; /ExitCode //结束进程 00401015 \. FF15 0C204000 call dword ptr ds:[<&KERNEL32.ExitProcess>] ; \ExitProcess 0040101B . C3 retn 0040101C 90 nop 2.-------------------------------------------------------------------------------------------- 学习一下设置api断点: 参看一下当前模块中的和消息有关的api函数: 名称位于 Anti-Spy 地址 区段 类型 ( 名称 注释 00402004 .rdata 导入 ( KERNEL32.CloseHandle 00402008 .rdata 导入 ( KERNEL32.CreateFileA 00402020 .rdata 导入 ( USER32.DialogBoxParamA 00402014 .rdata 导入 ( USER32.EndDialog 0040200C .rdata 导入 ( KERNEL32.ExitProcess 00402040 .rdata 导入 ( USER32.FindWindowA 00402024 .rdata 导入 ( USER32.GetDesktopWindow 00402038 .rdata 导入 ( USER32.GetDlgItem 00402000 .rdata 导入 ( KERNEL32.GetModuleHandleA 00402028 .rdata 导入 ( USER32.GetWindowRect 00402030 .rdata 导入 ( USER32.LoadIconA 00402034 .rdata 导入 ( USER32.MessageBoxA 00401000 .text 导出 0040201C .rdata 导入 ( USER32.MoveWindow 00402018 .rdata 导入 ( USER32.PostMessageA //*******1 0040202C .rdata 导入 ( USER32.SendDlgItemMessageA //是给对话里的控件发消息的,我们不需要,不管它. 0040203C .rdata 导入 ( USER32.SendMessageA //*******2 /********************************************************************** *********1看一下PostMessageA函数原型: The PostMessage function places (posts) a message in the message queue (消息队列)associated with the thread that created the specified window and then returns without waiting for the thread to process the message. Messages in a message queue are retrieved by calls to the GetMessage or PeekMessage function. 翻译: 把消息放到当前创建了一个特定窗口的线程的消息队列里,然后不等待次线程处理这个消息就返回. 消息队列里的消息通过调用GetMessage或PeekMessage函数来获得. BOOL PostMessage( HWND hWnd, // handle of destination window //当前窗口的句柄 UINT Msg, // message to post //要送走的消息 WPARAM wParam, // first message parameter //消息附加信息 LPARAM lParam // second message parameter //消息附加信息 ); Return Values 返回值 If the function succeeds, the return value is nonzero. //成功,返回非0 If the function fails, the return value is zero. //失败返回0 /********************************************************************** ********2看一下sendMessageA函数原型: The SendMessage function sends the specified message to a window or windows. The function calls the window procedure for the specified window and does not return until the window procedure has processed the message. The PostMessage function, in contrast, posts a message to a thread’s message queue and returns immediately. 翻译: SendMessage函数给一个窗口或多个串口发送一个特定的消息.函数调用这个特定窗口的窗口过程, 直到这个窗口过程处理了这个消息才返回.相对应的PostMessage函数是把消息发送到线程的消息队列里,并马上返回. LRESULT SendMessage( HWND hWnd, // handle of destination window //目标窗口的句柄 UINT Msg, // message to send //要发送的消息 WPARAM wParam, // first message parameter//消息附加信息 LPARAM lParam // second message parameter//消息附加信息 ); Return Values返回值 The return value specifies the result of the message processing and depends on the message sent. /********************************************************************** 好了,看了这两个函数,设断点试试. 首先PostMessageA,好了开始: 00402018 .rdata 导入 ( USER32.PostMessageA //******* //在这里,按enter键 来到参考位置: 参考位于Anti-Spy:.text 到 USER32.PostMessageA 00401060 call dword ptr ds:[<&USER32.PostMessageA>] USER32.PostMessageA 右键,选在每个命令上设断点,即bp PostMessageA 则发现任何操作都会中断到系统领空中. 中断太多了,不好用. 再试试sendMessageA,看解释它是给窗口过程发消息,并等待窗口过程处理消息,这正是我们需要的. 我们的目标是: 点了"检测"按钮,然后让程序处理这个消息,不就知道程序在干什么了吗.^_^ 方法问题如上所述: 找到: 参考位于Anti-Spy:.text 到 USER32.SendMessageA //有3处 00401103 call dword ptr ds:[<&USER32.SendMessageA>] USER32.SendMessageA // 会中断在系统领空 00401133 mov ebp,dword ptr ds:[<&USER32.SendMessageA>] USER32.SendMessageA // 停在此指令处 00401217 mov edi,dword ptr ds:[<&USER32.SendMessageA>] USER32.SendMessageA // 停在此指令处 右键,选在每个命令上设断点,即相当于在命令行bp SendMessageA,区别在于bp SendMessageA肯定会停在系统领空(即sendmessagea函数的第一条指令处), 而我们这种设断点的方法,会中断在那里,看上面的注释.这就是这两中设法的区别. 00401118 > \8B7424 34 mov esi,dword ptr ss:[esp 34] 0040111C . 8B1D 38204000 mov ebx,dword ptr ds:[<&USER32.GetDlgItem>] ; USER32.GetDlgItem 00401122 . 6A 00 push 0 ; /lParam = 0 00401124 . 6A 00 push 0 ; |wParam = 0 00401126 . 68 F0000000 push 0F0 ; |Message = BM_GETCHECK 0040112B . 68 FE030000 push 3FE ; |/ControlID = 3FE (1022.) //是那个可选钮的ID 00401130 . 56 push esi ; ||hWnd 00401131 . FFD3 call ebx ; |\GetDlgItem 00401133 . 8B2D 3C204000 mov ebp,dword ptr ds:[<&USER32.SendMessageA>] ; |USER32.SendMessageA //停在这里 00401139 . 50 push eax ; |hWnd 0040113A . FFD5 call ebp ; \SendMessageA 0040113C . 8B3D 34204000 mov edi,dword ptr ds:[<&USER32.MessageBoxA>] ; USER32.MessageBoxA 00401142 . 85C0 test eax,eax 00401144 . 74 24 je short Anti-Spy.0040116A 00401146 . E8 95010000 call Anti-Spy.004012E0 //进入 { 004012E0 /$Content$nbsp; 6A 00 push 0 ; /hTemplateFile = NULL 004012E2 |. 68 80000000 push 80 ; |Attributes = NORMAL 004012E7 |. 6A 03 push 3 ; |Mode = OPEN_EXISTING 004012E9 |. 6A 00 push 0 ; |pSecurity = NULL 004012EB |. 6A 03 push 3 ; |ShareMode = FILE_SHARE_READ|FILE_SHARE_WRITE 004012ED |. 68 000000C0 push C0000000 ; |Access = GENERIC_READ|GENERIC_WRITE 004012F2 |. 68 BC304000 push Anti-Spy.004030BC ; |FileName = "\\.\REGVXD" 004012F7 |. FF15 08204000 call dword ptr ds:[<&KERNEL32.CreateFileA>] ; \CreateFileA //打开驱动文件,返回句柄 004012FD |. 83F8 FF cmp eax,-1 //找到会返回此文件句柄 00401300 |. 74 0D je short Anti-Spy.0040130F //找到驱动,就不跳 00401302 |. 50 push eax ; /hObject 00401303 |. FF15 04204000 call dword ptr ds:[<&KERNEL32.CloseHandle>] ; \CloseHandle //关闭文件 00401309 |. B8 01000000 mov eax,1 0040130E |. C3 retn 0040130F |> 68 84304000 push Anti-Spy.00403084 ; /Title = "Registry Monitor - Sysinternals: www.sysinternals.com" 00401314 |. 6A 00 push 0 ; |Class = 0 00401316 |. FF15 40204000 call dword ptr ds:[<&USER32.FindWindowA>] ; \FindWindowA //实际是检查窗口标题 //找到符合条件的顶级窗口,就返回此窗口句柄 //没找到,返回0 0040131C |. F7D8 neg eax //求补码 0040131E |. 1BC0 sbb eax,eax //带借位减法 00401320 |. F7D8 neg eax //求补码 00401322 \. C3 retn 举例分析: eax=0x00000000时: neg eax ---> 0x00000000 CF=0 sbb eax,eax---> 0x00000000 - 0x00000000 -0=0x00000000 neg eax ---> 0x00000000 CF=0 eax=0x00000001时: neg eax ---> 0x00000001 CF=1 sbb eax,eax---> 0x00000001 - 0x00000001 -1=0xffffffff neg eax ---> 0x00000001 CF=1 就是说,返回0时,运算结果为0 返回非0时,运行结果为1 } 0040114B . 85C0 test eax,eax //判断一下 0040114D . 6A 30 push 30 0040114F . 74 0C je short Anti-Spy.0040115D //=0就跳,表示没找到regmon或filemon 00401151 . 68 80304000 push Anti-Spy.00403080 ; ASCII "OK" 00401156 . 68 6C304000 push Anti-Spy.0040306C ; ASCII "RegMON is Running! " 0040115B . EB 0A jmp short Anti-Spy.00401167 0040115D > 68 64304000 push Anti-Spy.00403064 ; ASCII "Error" 00401162 . 68 40304000 push Anti-Spy.00403040 ; ASCII "Can’t find RegMON with this method!" 00401167 > 56 push esi 00401168 . FFD7 call edi //USER32.MessageBoxA 0040116A > 6A 00 push 0 0040116C . 6A 00 push 0 0040116E . 68 F0000000 push 0F0 00401173 . 68 FF030000 push 3FF 00401178 . 56 push esi 00401179 . FFD3 call ebx 0040117B . 50 push eax 0040117C . FFD5 call ebp 0040117E . 85C0 test eax,eax 00401180 . 0F84 40010000 je Anti-Spy.004012C6 00401186 . E8 A5010000 call Anti-Spy.00401330 0040118B . 85C0 test eax,eax 0040118D . 6A 30 push 30 0040118F . 74 1C je short Anti-Spy.004011AD 00401191 . 68 80304000 push Anti-Spy.00403080 ; ASCII "OK" 00401196 . 68 28304000 push Anti-Spy.00403028 ; ASCII "FileMON is Running! " 0040119B . 56 push esi 0040119C . FFD7 call edi 0040119E . 5F pop edi 0040119F . 5E pop esi 004011A0 . 5D pop ebp 004011A1 . B8 01000000 mov eax,1 004011A6 . 5B pop ebx 004011A7 . 83C4 20 add esp,20 004011AA . C2 1000 retn 10 相关api函数: /**************************************************************** The CloseHandle function closes an open object handle. 关闭一个内核对象 BOOL CloseHandle( HANDLE hObject // handle to object to close ); Parameters hObject Identifies an open object handle. // 一个打开的对象的句柄标识 Return Values If the function succeeds, the return value is nonzero. //成功返回非0 If the function fails, the return value is zero. //失败返回0 /**************************************************************** The CreateFile function creates or opens the following objects and returns a handle that can be used to access the object: 创建或打开一个文件 HANDLE CreateFile( LPCTSTR lpFileName, // pointer to name of the file //指向文件名 DWORD dwDesiredAccess, // access (read-write) mode DWORD dwShareMode, // share mode LPSECURITY_ATTRIBUTES lpSecurityAttributes, // pointer to security attributes DWORD dwCreationDistribution, // how to create DWORD dwFlagsAndAttributes, // file attributes HANDLE hTemplateFile // handle to file with attributes to copy ); Return Values//成功返回句柄 If the function succeeds, the return value is an open handle to the specified file. If the specified file exists before the function call and dwCreationDistribution is CREATE_ALWAYS or OPEN_ALWAYS, a call to GetLastError returns ERROR_ALREADY_EXISTS (even though the function has succeeded). If the file does not exist before the call, GetLastError returns zero. If the function fails, the return value is INVALID_HANDLE_VALUE. To get extended error information, call GetLastError. /**************************************************************** The FindWindow function retrieves the handle to the top-level window whose class name and window name match the specified strings. This function does not search child windows. //翻译: FindWindow函数获得符合指定的类名和窗口名的顶级窗口的句柄. HWND FindWindow( LPCTSTR lpClassName, // pointer to class name 指向类名的指针 LPCTSTR lpWindowName // pointer to window name 指向窗口名的指针 ); Return Values //成功,返回这个窗口的句柄,失败返回NULL If the function succeeds, the return value is the handle to the window that has the specified class name and window name. If the function fails, the return value is NULL. To get extended error information, call GetLastError. ————————————————————————————————— 【总结】 仅以学习为目的,知识是宝贵的,破解是次要的。 有些程序,不经过消息循环,通过sendmessagea发送消息后,就开始执行相应的处理代码,对于窗口的操作(如点按钮),在不知道设什么断点时,可以使用一下BP sendmessagea试试!当然这个断点也并不是总是好用的! 分析程序时,多查查api函数,会了解更多的底层的东西。 另:这个程序不能设置消息断点,请教大侠们指点一下。 我认为按下一个按钮就会,发送一个WM_COMAND消息,在通过消息循环处理。这个程序怎么不行呢?不会是没经过消息循环吧,那么怎么拦截这个按钮? 请大侠们多指点了! 感谢你看完此菜文! |
|小黑屋|最新主题|手机版|微赢网络技术论坛 ( 苏ICP备08020429号 )
GMT+8, 2024-9-30 01:25 , Processed in 0.286095 second(s), 12 queries , Gzip On, MemCache On.
Powered by Discuz! X3.5
© 2001-2023 Discuz! Team.