隐藏api函数调用对于对付静态分析,不用说是非常有意义的,许多加壳软件在输入表上大做文章,其中有一个重要的作用就是让破解者在得到的反汇编代码中看不到正常的api函数调用。我做一个最简单的测试,在不借助加壳软件和虚拟机保护技术的情况下,用手写代码的方式来实现隐藏api函数调用。
先看看我要保护的代码:
代码:
#include "windows.h" int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow) { MessageBox(0,"Reverse Me","Test",0); return 0; }
1.最基本、最简单的方法:
代码:
#include "windows.h" typedef int (WINAPI *MYFUNC)(HWND hWnd,LPCTSTR lpText,LPCTSTR lpCaption,UINT uType); int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow) { 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"的加密形式。 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" HMODULE hMod=LoadLibrary("user32.dll"); if(hMod) { MYFUNC func=(MYFUNC)GetProcAddress(hMod,MsgBoxA); //获取MessageBoxA的函数地址。 func(0,lpText,lpCaption,0); //调用MessageBoxA函数。 FreeLibrary(hMod); } return 0; }
现在已经看不到赤裸裸的MessageBoxA了,而且IDA连个提示也不给了,但是调用的GetProcAddress函数同样是一个隐患,我们把它也隐藏起来:
代码:
。。。。。。 MYFUNC func=NULL; char * pFuncName; HMODULE hMod=LoadLibrary("user32.dll"); if(hMod) { PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)hMod; PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((ULONG)hMod+pDosHeader->e_lfanew); PIMAGE_OPTIONAL_HEADER32 pOptionalHeader = &(pNtHeader->OptionalHeader); PIMAGE_DATA_DIRECTORY pExportData = (PIMAGE_DATA_DIRECTORY)(&(pOptionalHeader->DataDirectory[0])); PIMAGE_EXPORT_DIRECTORY pExportTable = (PIMAGE_EXPORT_DIRECTORY)((ULONG)hMod+pExportData->VirtualAddress); ULONG * AddrFunctions=(ULONG *)((ULONG)hMod+pExportTable->AddressOfFunctions); ULONG * AddrNames=(ULONG *)((ULONG)hMod+pExportTable->AddressOfNames); for(i=0;i<pExportTable->NumberOfFunctions;i++) { pFuncName=(char *)((LONG)hMod+AddrNames[i]); if(strcmp(pFuncName,MsgBoxA)==0) { func=(MYFUNC)((LONG)hMod+AddrFunctions[i]); break; } } if(func) func(0,lpText,lpCaption,0); FreeLibrary(hMod); } 。。。。。。
现在连GetProcAddress也没有了,隐蔽性更好了,我们还想做得更隐蔽一点,用个简单的SMC:
代码:
#pragma comment(linker, "/SECTION:.text,ERW") void Decrypt(char * start,char * end) { for(char * i=start;i<end;i++) { (*i)^=0x11; } } 。。。。。。 Decrypt((char * )401000,(char * )400000); //两个需要更正的地址参数。 __asm inc eax __asm dec eax //16进制对应40 48 ,用来标记加密代码段起始地址 HMODULE hMod=LoadLibrary("user32.dll"); 。。。。。。 __asm inc eax __asm dec eax //16进制对应40 48,用来标记加密代码段末地址 return 0; 。。。。。。
到这里已经完成了一个简单的api函数隐藏,但是这些方法,主要用来对付静态分析,如果动态跟踪的话就容易原形毕露了.这是我在学习过程中的一点心得,希望看雪的朋友们能多多指教.