给C语言添加花指令,抵御反汇编

给C语言添加花指令,抵御反汇编  


(1)未加花程序 能正确反汇编
原程序:
 
   

void Function() {   Input++;   Output++;   Input+=Output;   printf("函数结果:%d,%d",Input,Output); } 反汇编代码: IDA .text:00401096                 rep stosd .text:00401098                 mov     eax, Input .text:0040109D                 add     eax, 1 .text:004010A0                 mov     Input, eax .text:004010A5                 mov     ecx, Output .text:004010AB                 add     ecx, 1 .text:004010AE                 mov     Output, ecx .text:004010B4                 mov     edx, Input .text:004010BA                 add     edx, Output .text:004010C0                 mov     Input, edx .text:004010C6                 mov     eax, Output .text:004010CB                 push    eax .text:004010CC                 mov     ecx, Input .text:004010D2                 push    ecx .text:004010D3                 push    offset s_PSDD   ; "函数结果:%d,%d" .text:004010D8                 call    printf

(2)简单加花后,在IDA中反汇编错误,在w32dasm中反汇编错误,但是在OD中反汇编正确
加花后程序:
 
   
 
   

void Function() {   _asm  jz label   _asm jnz label   _asm __emit   0e8h  //e8是call指令 label:   Input++;   Output++;   Input+=Output;   printf("函数结果:%d,%d",Input,Output); } OD中:   IDA中: .text:00401096                 rep stosd .text:00401098                 jz      short near ptr loc_40109C+1 .text:00401098 .text:0040109A                 jnz     short near ptr loc_40109C+1 .text:0040109A .text:0040109C .text:0040109C loc_40109C:                             ; CODE XREF: .text:00401098 j .text:0040109C                                         ; .text:0040109A j .text:0040109C                 call    near ptr 4275D142h .text:004010A1                 add     [ebx-3F5CFE40h], al .text:004010A7                 xor     eax, 0D8B0042h .text:004010AC                 mov     esp, 83004235h .text:004010B1                 rol     dword ptr [ecx], 89h .text:004010B4                 or      eax, offset Output .text:004010B9                 mov     edx, Input .text:004010BF                 add     edx, Output .text:004010C5                 mov     Input, edx .text:004010CB                 mov     eax, Output .text:004010D0                 push    eax .text:004010D1                 mov     ecx, Input .text:004010D7                 push    ecx .text:004010D8                 push    offset s_PSDD   ; "函数结果:%d,%d" .text:004010DD                 call    printf

 
   
(3)改进,加花后,IDA与OD均反汇编错误
改进后程序:
 
   
 
   

void Function() {   _asm xor eax,eax   _asm test eax,eax   _asm  jz label1   _asm jnz label0 label0:   _asm __emit   0e8h label1:   Input++;   Output++;   Input+=Output;   printf("函数结果:%d,%d",Input,Output); } OD中:   IDA中: .text:0040109C                 jz      short near ptr loc_4010A0+1 .text:0040109C .text:0040109E                 jnz     short $+2 .text:004010A0 .text:004010A0 loc_4010A0:                             ; CODE XREF: .text:0040109C j .text:004010A0                 call    near ptr 4275D146h .text:004010A5                 add     [ebx-3F5CFE40h], al .text:004010AB                 xor     eax, 0D8B0042h .text:004010B0                 mov     esp, 83004235h .text:004010B5                 rol     dword ptr [ecx], 89h .text:004010B8                 or      eax, offset Output .text:004010BD                 mov     edx, Input .text:004010C3                 add     edx, Output .text:004010C9                 mov     Input, edx .text:004010CF                 mov     eax, Output .text:004010D4                 push    eax .text:004010D5                 mov     ecx, Input .text:004010DB                 push    ecx .text:004010DC                 push    offset s_PSDD   ; "函数结果:%d,%d" .text:004010E1                 call    printf

 
   
应用
(1)  简单加花
实现简单,但是原理比较简单,高手很容易就能去除,一般以消耗攻击者的耐性来达到目的。
(2)复杂加花
类似于加壳
1.  记录程序的原入口点,
2.  找到PE文件的空白区域,在空白区域内写入花指令(或者添加新节)
3.  把入口点地址改为新入口地址
4.  花指令执行完后跳转到原入口点地址
在程序执行时,程序将从新的入口地址执行,即花指令先被执行,然后再执行程序原来的入口地址功能。
增加了静态分析的难度,提高了代码的信息隐藏效果,该方法一般应用于病毒的免杀中。
 
   
 
   
 
   
2.  隐藏API
逆向分析工作人员往往就是通过API在极短时间内获取了大量信息,从而使他们成功定位目标程序的关键代码段。所以隐藏对API 的调用可以有效地提高程序的抗分析能力。
例如一个简单的程序:
 
   

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int       nCmdShow) {   MessageBox(NULL,"test","box",0);   return 0; } 反汇编代码如下: .text:00401028                 mov     esi, esp .text:0040102A                 push    0               ; uType .text:0040102C                 push    offset Caption  ; "Test" .text:00401031                 push    offset Text     ; "Reverse Me" .text:00401036                 push    0               ; hWnd .text:00401038                 call    ds:MessageBoxA(x,x,x,x)

目的是让反汇编的代码看不到 ds: MessageBoxA(x,x,x,x) 这样的提示。
1.最基本、最简单的方法:
 
   

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int       nCmdShow) {   /********************************************************   1. 定义字符串   ********************************************************/   TCHAR MsgBoxA[MAX_PATH]="MessageBoxA";   /********************************************************   2. 获取MessageBoxA的函数地址   ********************************************************/   HMODULE hMod=LoadLibrary("user32.dll");   MYFUNC func=(MYFUNC)GetProcAddress(hMod,MsgBoxA);//获取MessageBoxA的函数地址。   func(0,"Reverse Me","Test",0);  //调用MessageBoxA函数。   FreeLibrary(hMod);   return 0; } IDA中(V5.4 .text:0040102E                 mov     eax, dword ptr ds:aMessageboxa ; "MessageBoxA" .text:00401033                 mov     dword ptr [ebp+ProcName], eax .text:00401039                 mov     ecx, dword ptr ds:aMessageboxa+4 .text:0040103F                 mov     [ebp+var_100], ecx .text:00401045                 mov     edx, dword ptr ds:aMessageboxa+8 .text:0040104B                 mov     [ebp+var_FC], edx .text:00401051                 mov     ecx, 3Eh .text:00401056                 xor     eax, eax .text:00401058                 lea     edi, [ebp+var_F8] .text:0040105E                 rep stosd .text:00401060                 mov     esi, esp .text:00401062                 push    offset LibFileName ; "user32.dll" .text:00401067                 call    ds:__imp__LoadLibraryA@4 ; LoadLibraryA(x) .text:0040106D                 cmp     esi, esp .text:0040106F                 call    __chkesp .text:00401074                 mov     [ebp+hLibModule], eax .text:0040107A                 mov     esi, esp .text:0040107C                 lea     eax, [ebp+ProcName] .text:00401082                 push    eax             ; lpProcName .text:00401083                 mov     ecx, [ebp+hLibModule] .text:00401089                 push    ecx             ; hModule .text:0040108A                 call    ds:__imp__GetProcAddress@8 ; GetProcAddress(x,x) .text:00401090                 cmp     esi, esp .text:00401092                 call    __chkesp .text:00401097                 mov     [ebp+var_10C], eax .text:0040109D                 mov     esi, esp .text:0040109F                 push    0 .text:004010A1                 push    offset aTest    ; "Test" .text:004010A6                 push    offset aReverseMe ; "Reverse Me" .text:004010AB                 push    0 .text:004010AD                 call    [ebp+var_10C] OD中:

3.  进行简单加密处理
隐藏字符串"MessageBoxA","Reverse Me","Test"
 
   

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int       nCmdShow) {   /********************************************************   1. 加密字符串   ********************************************************/   char MsgBoxA[]={0x5c,0x74,0x62,0x62,0x70,0x76,0x74,0x53,0x7e,0x69,0x50,0x00};   //字符串"MessageBoxA"的加密形式。   char lpText[]={0x43,0x74,0x67,0x74,0x63,0x62,0x74,0x31,0x5C,0x74,0x00};    //字符串"Reverse Me"的加密形式。   char lpCaption[]={0x45,0x74,0x62,0x65,0x00};    //字符串"Test"的加密形式。   /********************************************************   2. 解密字符串   ********************************************************/   for(int i=0;i<strlen(MsgBoxA);i++)       MsgBoxA[i]^=0x11;  //解密字符串"MessageBoxA"   for(i=0;i<strlen(lpText);i++)         lpText[i]^=0x11;  //解密字符串"Reverse Me"     for(i=0;i<strlen(lpCaption);i++)       lpCaption[i]^=0x11;  //解密字符串"Test"   /********************************************************   3. 获取MessageBoxA的函数地址   ********************************************************/   HMODULE hMod=LoadLibrary("user32.dll");   if(hMod)   {     MYFUNC func=(MYFUNC)GetProcAddress(hMod,MsgBoxA); //获取MessageBoxA()的函数地址。     func(0,lpText,lpCaption,0);  //调用MessageBoxA函数。     FreeLibrary(hMod);   }   return 0; }  IDA中: .text:0040146E                 mov     edx, [ebp+arg_8] .text:00401471                 push    edx .text:00401472                 mov     eax, [ebp+arg_4] .text:00401475                 push    eax .text:00401476                 push    offset s_SecondChanceA ; "Second Chance Assertion Failed: File %s"... .text:0040147B                 lea     ecx, [ebp+OutputString] .text:00401481                 push    ecx .text:00401482                 call    dword_4235D0 OD中:

3.将GetProcAddress也隐藏
类似上面的方法
 
   

4.简单的SMC
 
   

  /********************************************************   3. 获取MessageBoxA的函数地址   ********************************************************/   Decrypt((char * )404445,(char * )404543);   __asm inc eax     __asm dec eax   HMODULE hMod=LoadLibrary("user32.dll");   if(hMod)   {     MYFUNC func=(MYFUNC)GetProcAddress(hMod,MsgBoxA); //获取MessageBoxA()的函数地址。     func(0,lpText,lpCaption,0);  //调用MessageBoxA函数。     FreeLibrary(hMod);   }   __asm inc eax     __asm dec eax

 
   


二.抗动态调试技术
动态调试,也就是使用调试器等工具对软件的运行进行跟踪,从而对关键代码进行逆向工程,或者干脆破坏软件中的保护措施,对软件进行盗版,抗动态调试即阻碍这个逆向过程。
反调试目的:主要针对OD等调试跟踪程序,检测内存或者进程中是否有调试软件运行,进而让这些程序失效或者直接失去响应。检测自身是否运行在调试器下。
1.调用Win32API检测程序是否处于调试状态
 
   

IsDebuggerPresentFlag() 

 
   
 
   

//  IsDebuggerPresentFlag // 返回值为true时检测到调试器,否则无调试器 /* bool IsDebuggerPresentFlag() {    HINSTANCE hInst = LoadLibrary("kernel32.dll");    if(hInst!=NULL)    {      FARPROC pIsDebuggerPresent=GetProcAddress(hInst,"IsDebuggerPresent");      if(pIsDebuggerPresent!=NULL)        return pIsDebuggerPresent();    }    return FALSE; }

也可以自实现,

 
   

bool IsDebuggerPresentFlag() {   __asm    {       mov eax, fs:[0x30]            //在位于TEB偏移30h处获得PEB地址     movzx eax, byte ptr [eax+2] //获得PEB偏移2h处BeingDebugged的值     test eax, eax     jne rt_label     jmp rf_label   } rt_label:     return true; rf_label:     return false; }

测试结果:该方法太古老,在OD中不能检测




 
   

NtGlobalFlags()  //  NtGlobalFlags,可检测出检测OllyDebug // 返回值为true时检测到调试器,否则无调试器 bool NtGlobalFlags() {   __asm   {     mov eax, fs:[30h]     mov eax, [eax+68h]     and eax, 0x70           test eax, eax     jne rt_label     jmp rf_label   } rt_label:     return true; rf_label:     return false; }

在OD中能检测,但是用OD的插件能够去掉(HideOD插件选上后不能检测,选上auto to run hideod 以及hideNtDebugBit)



 
   

HeapFlags() //  HeapFlags // 返回值为true时检测到调试器,否则无调试器 bool HeapFlags() {   __asm   {     mov eax, fs:[30h]     mov eax, [eax+18h] ;PEB.ProcessHeap     mov eax, [eax+0ch] ;PEB.ProcessHeap.ForceFlags     cmp eax, 2     jne rt_label     jmp rf_label   } rt_label:     return true; rf_label:     return false; }

在OD中,能检测,但是用OD的插件能够去掉(HideOD插件选上后不能检测,选上auto to run hideod以及hideNtDebugBit)




 
   

RemoteDebuggerPresent() //  RemoteDebuggerPresent // 返回值为true时检测到调试器,否则无调试器 typedef BOOL (WINAPI *CHECK_REMOTE_DENUGGER_PRESENT)(HANDLE,PBOOL); BOOL RemoteDebuggerPresent() {   BOOL    bDebuggerPresent=FALSE;   CHECK_REMOTE_DENUGGER_PRESENT CheckRemoteDebuggerPresent;      HMODULE hModule = GetModuleHandle("kernel32.dll");   if (hModule==INVALID_HANDLE_VALUE)   {     return FALSE;   }      CheckRemoteDebuggerPresent =(CHECK_REMOTE_DENUGGER_PRESENT)GetProcAddress(hModule, "CheckRemoteDebuggerPresent");   if( CheckRemoteDebuggerPresent(GetCurrentProcess(),&bDebuggerPresent))   {     return bDebuggerPresent;   }   return FALSE; }

在OD中,能检测,但是用OD的插件能够去掉(hideOd插件选上后不能测试,选上CheckRemoteDebuggerPresent)

你可能感兴趣的:(C/C++)