学着分析一个老样本的时候,发现了这个段anti-debug函数,鉴于WinSDK掌握不足,所以就慢慢分析了下。
概述:1、简单分析了这个anti-debug的流程;2、介绍下用到的Win函数,其中重点是如何获取运行中进程snapshot。
一、这个anti-debug非常老,如今OD的一堆插件绝对可以秒杀掉。只是简单的调用了"IsDebuggerPresent"函数,判断父进程,还有遍历所有进程判断是否有调试器(通过进程标题名称)。
1、LoadLibraryW函数原型(http://msdn.microsoft.com/en-us/library/windows/desktop/ms684175(v=vs.85).aspx)如下:
HMODULE WINAPI LoadLibrary( __in LPCTSTR lpFileName );
2、GetProcAddress函数原型(http://msdn.microsoft.com/en-us/library/windows/desktop/ms683212(v=vs.85).aspx)如下:
FARPROC WINAPI GetProcAddress( __in HMODULE hModule, __in LPCSTR lpProcName );
代码如下:
.text:71001000 .text:71001000 ; Attributes: bp-based frame fpd=78h .text:71001000 .text:71001000 Anti_debug proc near ; CODE XREF: kill_SecProcess+4Cp .text:71001000 ; DllEntryPoint+11p ... .text:71001000 .text:71001000 pe = PROCESSENTRY32 ptr -128h .text:71001000 .text:71001000 push ebp .text:71001001 lea ebp, [esp-78h] .text:71001005 sub esp, 128h .text:7100100B push ebx .text:7100100C push esi .text:7100100D mov esi, ds:LoadLibraryW .text:71001013 push edi .text:71001014 push offset ProcName ; "IsDebuggerPresent" .text:71001019 mov ebx, offset LibFileName ; "kernel32.dll" .text:7100101E push ebx ; lpLibFileName .text:7100101F call esi ; LoadLibraryW .text:71001021 mov edi, ds:GetProcAddress ; 得到IsDebuggerPresent的地址 .text:71001027 push eax ; hModule .text:71001028 call edi ; GetProcAddress .text:7100102A push offset aGetcurrentproc ; "GetCurrentProcessId" .text:7100102F push ebx ; lpLibFileName .text:71001030 mov g_Kernel, eax .text:71001035 call esi ; LoadLibraryW .text:71001037 push eax ; hModule .text:71001038 call edi ; GetProcAddress .text:7100103A xor edi, edi .text:7100103C push edi ; th32ProcessID .text:7100103D push 2 ; dwFlags .text:7100103F mov ebx, eax .text:71001041 call CreateToolhelp32Snapshot .text:71001046 mov esi, eax .text:71001048 lea eax, [ebp+78h+pe] .text:7100104E push eax ; lppe .text:7100104F push esi ; hSnapshot .text:71001050 mov [ebp+78h+pe.dwSize], 128h .text:7100105A call Process32First .text:7100105F .text:7100105F DO_BEGIN: ; CODE XREF: Anti_debug+78j .text:7100105F call ebx .text:71001061 cmp [ebp+78h+pe.th32ProcessID], eax ; 获得本进程信息 .text:71001067 jz short Break ; 检测父进程ID .text:71001069 lea eax, [ebp+78h+pe] .text:7100106F push eax ; lppe .text:71001070 push esi ; hSnapshot .text:71001071 call Process32Next .text:71001076 test eax, eax .text:71001078 jnz short DO_BEGIN .text:7100107A jmp short loc_71001094 .text:7100107C ; --------------------------------------------------------------------------- .text:7100107C .text:7100107C Break: ; CODE XREF: Anti_debug+67j .text:7100107C mov edi, [ebp+78h+pe.th32ParentProcessID] ; 检测父进程ID .text:71001082 cmp edi, 4 ; 如果父进程System进程,表明正常运行 .text:71001085 jz Security ; 安全,没有被调试 .text:7100108B cmp edi, 8 ; ID号为8的是哪个进程 .text:7100108E jz Security .text:71001094 .text:71001094 loc_71001094: ; CODE XREF: Anti_debug+7Aj .text:71001094 lea eax, [ebp+78h+pe] .text:7100109A push eax ; lppe .text:7100109B push esi ; hSnapshot .text:7100109C call Process32First ; 再次检测当前进程 .text:710010A1 .text:710010A1 loc_710010A1: ; CODE XREF: Anti_debug+14Aj .text:710010A1 cmp [ebp+78h+pe.th32ProcessID], edi .text:710010A7 jnz loc_7100113B .text:710010AD lea eax, [ebp+78h+pe.szExeFile] .text:710010B3 push eax ; int .text:710010B4 push offset String ; "OllyDbg.exe" .text:710010B9 call Is_EqualString .text:710010BE test eax, eax .text:710010C0 pop ecx .text:710010C1 pop ecx .text:710010C2 jz Security .text:710010C8 lea eax, [ebp+78h+pe.szExeFile] .text:710010CE push eax ; int .text:710010CF push offset aOllyice_exe ; "OllyICE.exe" .text:710010D4 call Is_EqualString .text:710010D9 test eax, eax .text:710010DB pop ecx .text:710010DC pop ecx .text:710010DD jz short Security .text:710010DF lea eax, [ebp+78h+pe.szExeFile] .text:710010E5 push eax ; int .text:710010E6 push offset aPeditor_exe ; "PEditor.exe" .text:710010EB call Is_EqualString .text:710010F0 test eax, eax .text:710010F2 pop ecx .text:710010F3 pop ecx .text:710010F4 jz short Security .text:710010F6 lea eax, [ebp+78h+pe.szExeFile] .text:710010FC push eax ; int .text:710010FD push offset aLordpe_exe ; "LordPE.exe" .text:71001102 call Is_EqualString .text:71001107 test eax, eax .text:71001109 pop ecx .text:7100110A pop ecx .text:7100110B jz short Security .text:7100110D lea eax, [ebp+78h+pe.szExeFile] .text:71001113 push eax ; int .text:71001114 push offset aC32asm_exe ; "C32Asm.exe" .text:71001119 call Is_EqualString .text:7100111E test eax, eax .text:71001120 pop ecx .text:71001121 pop ecx .text:71001122 jz short Security .text:71001124 lea eax, [ebp+78h+pe.szExeFile] .text:7100112A push eax ; int .text:7100112B push offset aImportrec_exe ; "ImportREC.exe" .text:71001130 call Is_EqualString .text:71001135 test eax, eax .text:71001137 pop ecx .text:71001138 pop ecx .text:71001139 jz short Security .text:7100113B .text:7100113B loc_7100113B: ; CODE XREF: Anti_debug+A7j .text:7100113B lea eax, [ebp+78h+pe] .text:71001141 push eax ; lppe .text:71001142 push esi ; hSnapshot .text:71001143 call Process32Next .text:71001148 test eax, eax .text:7100114A jnz loc_710010A1 .text:71001150 call g_Kernel .text:71001156 test eax, eax .text:71001158 pop edi .text:71001159 pop esi .text:7100115A pop ebx .text:7100115B jz short loc_71001165 .text:7100115D .text:7100115D Security: ; CODE XREF: Anti_debug+85j .text:7100115D ; Anti_debug+8Ej ... .text:7100115D push 0 ; uExitCode .text:7100115F call ds:ExitProcess .text:71001165 ; --------------------------------------------------------------------------- .text:71001165 .text:71001165 loc_71001165: ; CODE XREF: Anti_debug+15Bj .text:71001165 xor eax, eax .text:71001167 add ebp, 78h .text:7100116A leave .text:7100116B retn .text:7100116B Anti_debug endp ; sp-analysis failed .text:7100116B .text:7100116C
二、这个snapshot术语刚刚接触到,值得学习。
(另一种获取当前进程信息方法在博文http://blog.csdn.net/betabin/article/details/7483939)
1、接触PROCESSENTRY32结构,其原型如下:
typedef struct tagPROCESSENTRY32 { DWORD dwSize; DWORD cntUsage; DWORD th32ProcessID; ULONG_PTR th32DefaultHeapID; DWORD th32ModuleID; DWORD cntThreads; DWORD th32ParentProcessID; LONG pcPriClassBase; DWORD dwFlags; TCHAR szExeFile[MAX_PATH]; } PROCESSENTRY32, *PPROCESSENTRY32;
这个结构是用于进行快照时,描述一个驻留于系统地址空间的进程列表。其中size在使用前要初始化为sizeof(PROCESSENTRY32)。
2、至于接下来的Process32First函数,则是开始遍历进程了。原型如下:
BOOL WINAPI Process32First( __in HANDLE hSnapshot, __inout LPPROCESSENTRY32 lppe );
也果断摘录了MSDN里的一个例程代码如下:
#include <windows.h> #include <tlhelp32.h> #include <tchar.h> // Forward declarations: BOOL GetProcessList( ); BOOL ListProcessModules( DWORD dwPID ); BOOL ListProcessThreads( DWORD dwOwnerPID ); void printError( TCHAR* msg ); int main( void ) { GetProcessList( ); return 0; } BOOL GetProcessList( ) { HANDLE hProcessSnap; HANDLE hProcess; PROCESSENTRY32 pe32; DWORD dwPriorityClass; // Take a snapshot of all processes in the system. hProcessSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 ); if( hProcessSnap == INVALID_HANDLE_VALUE ) { printError( TEXT("CreateToolhelp32Snapshot (of processes)") ); return( FALSE ); } // Set the size of the structure before using it. pe32.dwSize = sizeof( PROCESSENTRY32 ); // Retrieve information about the first process, // and exit if unsuccessful if( !Process32First( hProcessSnap, &pe32 ) ) { printError( TEXT("Process32First") ); // show cause of failure CloseHandle( hProcessSnap ); // clean the snapshot object return( FALSE ); } // Now walk the snapshot of processes, and // display information about each process in turn do { _tprintf( TEXT("\n\n=====================================================" )); _tprintf( TEXT("\nPROCESS NAME: %s"), pe32.szExeFile ); _tprintf( TEXT("\n-------------------------------------------------------" )); // Retrieve the priority class. dwPriorityClass = 0; hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, pe32.th32ProcessID ); if( hProcess == NULL ) printError( TEXT("OpenProcess") ); else { dwPriorityClass = GetPriorityClass( hProcess ); if( !dwPriorityClass ) printError( TEXT("GetPriorityClass") ); CloseHandle( hProcess ); } _tprintf( TEXT("\n Process ID = 0x%08X"), pe32.th32ProcessID ); _tprintf( TEXT("\n Thread count = %d"), pe32.cntThreads ); _tprintf( TEXT("\n Parent process ID = 0x%08X"), pe32.th32ParentProcessID ); _tprintf( TEXT("\n Priority base = %d"), pe32.pcPriClassBase ); if( dwPriorityClass ) _tprintf( TEXT("\n Priority class = %d"), dwPriorityClass ); // List the modules and threads associated with this process ListProcessModules( pe32.th32ProcessID ); ListProcessThreads( pe32.th32ProcessID ); } while( Process32Next( hProcessSnap, &pe32 ) ); CloseHandle( hProcessSnap ); return( TRUE ); } BOOL ListProcessModules( DWORD dwPID ) { HANDLE hModuleSnap = INVALID_HANDLE_VALUE; MODULEENTRY32 me32; // Take a snapshot of all modules in the specified process. hModuleSnap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, dwPID ); if( hModuleSnap == INVALID_HANDLE_VALUE ) { printError( TEXT("CreateToolhelp32Snapshot (of modules)") ); return( FALSE ); } // Set the size of the structure before using it. me32.dwSize = sizeof( MODULEENTRY32 ); // Retrieve information about the first module, // and exit if unsuccessful if( !Module32First( hModuleSnap, &me32 ) ) { printError( TEXT("Module32First") ); // show cause of failure CloseHandle( hModuleSnap ); // clean the snapshot object return( FALSE ); } // Now walk the module list of the process, // and display information about each module do { _tprintf( TEXT("\n\n MODULE NAME: %s"), me32.szModule ); _tprintf( TEXT("\n Executable = %s"), me32.szExePath ); _tprintf( TEXT("\n Process ID = 0x%08X"), me32.th32ProcessID ); _tprintf( TEXT("\n Ref count (g) = 0x%04X"), me32.GlblcntUsage ); _tprintf( TEXT("\n Ref count (p) = 0x%04X"), me32.ProccntUsage ); _tprintf( TEXT("\n Base address = 0x%08X"), (DWORD) me32.modBaseAddr ); _tprintf( TEXT("\n Base size = %d"), me32.modBaseSize ); } while( Module32Next( hModuleSnap, &me32 ) ); CloseHandle( hModuleSnap ); return( TRUE ); } BOOL ListProcessThreads( DWORD dwOwnerPID ) { HANDLE hThreadSnap = INVALID_HANDLE_VALUE; THREADENTRY32 te32; // Take a snapshot of all running threads hThreadSnap = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 ); if( hThreadSnap == INVALID_HANDLE_VALUE ) return( FALSE ); // Fill in the size of the structure before using it. te32.dwSize = sizeof(THREADENTRY32); // Retrieve information about the first thread, // and exit if unsuccessful if( !Thread32First( hThreadSnap, &te32 ) ) { printError( TEXT("Thread32First") ); // show cause of failure CloseHandle( hThreadSnap ); // clean the snapshot object return( FALSE ); } // Now walk the thread list of the system, // and display information about each thread // associated with the specified process do { if( te32.th32OwnerProcessID == dwOwnerPID ) { _tprintf( TEXT("\n\n THREAD ID = 0x%08X"), te32.th32ThreadID ); _tprintf( TEXT("\n Base priority = %d"), te32.tpBasePri ); _tprintf( TEXT("\n Delta priority = %d"), te32.tpDeltaPri ); _tprintf( TEXT("\n")); } } while( Thread32Next(hThreadSnap, &te32 ) ); CloseHandle( hThreadSnap ); return( TRUE ); } void printError( TCHAR* msg ) { DWORD eNum; TCHAR sysMsg[256]; TCHAR* p; eNum = GetLastError( ); FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, eNum, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language sysMsg, 256, NULL ); // Trim the end of the line and terminate it with a null p = sysMsg; while( ( *p > 31 ) || ( *p == 9 ) ) ++p; do { *p-- = 0; } while( ( p >= sysMsg ) && ( ( *p == '.' ) || ( *p < 33 ) ) ); // Display the message _tprintf( TEXT("\n WARNING: %s failed with error %d (%s)"), msg, eNum, sysMsg ); }