年底了,又赶上离职潮了。离职的coder总想着带走一些代码,自己的无可厚非,别人的就不大好了。如何保护公司的重要代码成了头痛的问题。本文通过添加一些简单的手段保护重要的代码。当然,这些手段有些陈旧,对付老鸟基本无效,但一般的coder拿到这样的代码,只能按delete了。。。吗啡,在药师手上变成了麻醉药,但在瘾君子看来又是一顿饕餮,这些手段如果被离职的coder自己使用,不仅制造bug还代码保护,那交接的coder又要抓狂了~
这里做一些约定VS编译器去除了/Gz 选项(函数调用后检查堆栈),并启用非增量连接方式。
//V1 假设CriticalCodeV1是核心代码 需要隐藏其实现 __declspec(naked) void CriticalCodeV1() { MessageBox(NULL,"Cap","Msg",MB_OK); ExitProcess(0); } void CriticalCodeEnd() { } int main() { CriticalCodeV1(); }CriticalCodeV1是我的核心代码,假设这个代码被人觊觎(事实不会)。在文章的结尾,这段代码会被我隐藏的面目全非。
现在逐步开始隐藏代码:
DWORD MsgBoxAddr; DWORD ExitProcAddr; __declspec(naked) void CriticalCodeV2() { //因为函数声明为裸函数 不会自动生成函数框架 //因此需要自己保存函数框架和开辟堆空间 __asm { push ebp; mov ebp,esp; sub esp,0x10; mov al,'C'; mov [ebp-0x04],al; mov al,'a'; mov [ebp-0x03],al; mov al,'p'; mov [ebp-0x02],al; xor eax,eax; mov [ebp-0x01],al; mov al, 'M'; mov [ebp-0x08],al; mov al,'s'; mov [ebp-0x07],al; mov al, 'g'; mov [ebp-0x06],al; xor eax,eax; mov [ebp-0x05],al; push 0x00; lea eax,[ebp-0x04] push eax; //push "cap" lea eax,[ebp-0x08] push eax; //push "Msg" push 0x00; //不同机器 MessageBoxA ExitProcess入口地址不同 需要重定位 //此处为了方便 直接硬编码 mov eax,0x749AFD1E; call eax; push 0x00; mov eax,0x768F79D8; call eax; } } void CriticalCodeEnd() { } int main() { HMODULE hU32Mod = LoadLibrary("user32.dll"); MsgBoxAddr = (DWORD)GetProcAddress(hU32Mod,"MessageBoxA"); HMODULE hKrlMod = LoadLibrary("kernel32.dll"); ExitProcAddr = (DWORD)GetProcAddress(hKrlMod,"ExitProcess"); //反汇编 记录函数地址的内容 CriticalCodeV2(); }这段代码仅仅是一个过渡,用来生成后续的ShellCode。注释中已经写到同样的API在不同的机器上入口地址不同,因此需要重定位,如何重定位?反汇编后记录Call指令之后EIP跳转到一个jmp指令,jmp指令的目标地址就是你机器上API函数的入口,用你的地址替换我的地址。当然,最好的办法是通过PE文件导入表获取,不过这样就不是简单的保护方式了;另外,毕竟是自己的代码,在代码中获得本机API入口还是比较方便的,因此用LoadLibrary(/GetProcAddress)直接加载。啊真是简单粗暴而又有效的方法~
//V3 将V2中的OpCode写入数组,初步隐藏关键代码。创建读写可执行的页,然后跳转到该页执行 int main() { DWORD writtenNum=0; DWORD CriticalCodeLen = 0x50; //shellcode 写到这 谁能一眼看出是什么鸟语 char CriticalCodeSCSrc[] = {"\x55\x8B\xEC\x83\xEC\x10\xB0\x43" \ "\x88\x45\xFC\xB0\x61\x88\x45\xFD" \ "\xB0\x70\x88\x45\xFE\x33\xC0\x88" \ "\x45\xFF\xB0\x4D\x88\x45\xF8\xB0" \ "\x73\x88\x45\xF9\xB0\x67\x88\x45" \ "\xFA\x33\xC0\x88\x45\xFB\x6A\x00" \ "\x8D\x45\xFC\x50\x8D\x45\xF8\x50" \ "\x6A\x00\xB8\x1E\xFD\x9A\x74\xFF" \ "\xD0\x6A\x00\xB8\xD8\x79\x8F\x76" \ "\xFF\xD0\xCC\xCC\xCC\xCC\xCC\xCC"}; char* SMCPtr = (char*)VirtualAllocEx(GetCurrentProcess(),NULL,0x1000,MEM_COMMIT,PAGE_EXECUTE_READWRITE); assert(SMCPtr); int state = WriteProcessMemory(GetCurrentProcess(),SMCPtr,CriticalCodeSCSrc,CriticalCodeLen,&writtenNum); assert(state); HMODULE hU32Mod = LoadLibrary("user32.dll"); HMODULE hKrlMod = LoadLibrary("kernel32.dll"); __asm { //这句的效果等于 call SMCPtr push SMCPtr; jmp [esp]; } }程序写到这,CriticalCodeV2已经被数组CriticalCodeSCSrcEnc中的内容取代,一眼看去不知CriticalCodeSCSrcEnc所云何物。不过只要跟着jmp [esp]一起跳转到SMCPtr的地址,就能看到程序正在做啥,更进一步,还可以把代码全记录下来,copy到静态汇编工具慢慢看。
//V4 对数组进行加密,直到关键代码段执行前才解密,进一步隐藏源码 void DeCode(char* SMCPtr,DWORD SMCLen) { for(DWORD i=0;i<SMCLen;i++) { SMCPtr[i] ^= 0xcc; } } int main() { DWORD writtenNum=0; DWORD CriticalCodeLen = 0x50; //CriticalCodeSCSrcEnc将原CriticalCodeSCSrc中的与0xcc异或 生成新的编码 //运行前先与0xcc异或解密 char CriticalCodeSCSrcEnc[] = {"\x99\x47\x20\x4F\x20\xDC\x7C\x8F" \ "\x44\x89\x30\x7C\xAD\x44\x89\x31" \ "\x7C\xBC\x44\x89\x32\xFF\x0C\x44" \ "\x89\x33\x7C\x81\x44\x89\x34\x7C" \ "\xBF\x44\x89\x35\x7C\xAB\x44\x89" \ "\x36\xFF\x0C\x44\x89\x37\xA6\xCC" \ "\x41\x89\x30\x9C\x41\x89\x34\x9C" \ "\xA6\xCC\x74\xD2\x31\x56\xB8\x33" \ "\x1C\xA6\xCC\x74\x14\xB5\x43\xBA" \ "\x33\x1C\x00\x00\x00\x00\x00\x00"}; char* SMCPtr = (char*)VirtualAllocEx(GetCurrentProcess(),NULL,0x1000,MEM_COMMIT,PAGE_EXECUTE_READWRITE); assert(SMCPtr); int state = WriteProcessMemory(GetCurrentProcess(),SMCPtr,CriticalCodeSCSrcEnc,CriticalCodeLen,&writtenNum); assert(state); HMODULE hU32Mod = LoadLibrary("user32.dll"); HMODULE hKrlMod = LoadLibrary("kernel32.dll"); DeCode(SMCPtr,CriticalCodeLen); __asm { push SMCPtr; jmp [esp]; } }既然,上面可以把隐藏的代码记录下来慢慢分析,那我只能把CriticalCodeSCSrcEnc中的内容加密,在运行DeCode后才解密全部内容,让观察者不能尽兴~加密方式是CriticalCodeSCSrcEnc与0xCC异或。不过问题又来了,这解密函数是明文,观察者自己解密,又能慢慢看了,还真是藏头露尾的办法。下面对解密部分略作修改,办法如V2/V3
//V4中 解密部分源码是为加密的 这等于CriticalCodeSCSrcEnc没有保护 //因此 需要把解密部分的代码也隐藏起来 这段就不用抑或了 要不然又要有人去解密这段代码了 //在V5中将使用V4 DeCode部分实现的OpCode __declspec(naked) void DeCodeSMC(char* SMCPtr,DWORD SMCLen) { __asm { //[ebp+0]:ebp [ebp+0x04]:retAddtr [ebp+0x08]:SMCPtr [ebp+0x0C]:SMCLen push ebp; mov ebp,esp; sub esp,0x10; //[ebp-4]:DWORD i; mov [ebp-4],0x00; mov [ebp-3],0x00; mov [ebp-2],0x00; mov [ebp-1],0x00; jmp Lab2; Lab1: mov eax,[ebp-4]; inc eax; mov [ebp-4],eax Lab2: mov ecx,[ebp-4]; cmp ecx,[ebp+0Ch]; jae Lab3; mov edx,[ebp+8]; add edx,[ebp-4]; mov al,[edx]; xor al,0xCC; mov ecx,[ebp+8]; add ecx,[ebp-4]; mov [ecx],al; jmp Lab1; Lab3: mov esp,ebp; pop ebp; ret 8 } } int main() { DWORD writtenNum=0; DWORD CriticalCodeLen = 0x50; //CriticalCodeSCSrcEnc将原CriticalCodeSCSrc中的与0xcc异或 生成新的编码 //运行前先与0xcc异或解密 char CriticalCodeSCSrcEnc[] = {"\x99\x47\x20\x4F\x20\xDC\x7C\x8F" \ "\x44\x89\x30\x7C\xAD\x44\x89\x31" \ "\x7C\xBC\x44\x89\x32\xFF\x0C\x44" \ "\x89\x33\x7C\x81\x44\x89\x34\x7C" \ "\xBF\x44\x89\x35\x7C\xAB\x44\x89" \ "\x36\xFF\x0C\x44\x89\x37\xA6\xCC" \ "\x41\x89\x30\x9C\x41\x89\x34\x9C" \ "\xA6\xCC\x74\xD2\x31\x56\xB8\x33" \ "\x1C\xA6\xCC\x74\x14\xB5\x43\xBA" \ "\x33\x1C\x00\x00\x00\x00\x00\x00"}; char* SMCPtr = (char*)VirtualAllocEx(GetCurrentProcess(),NULL,0x1000,MEM_COMMIT,PAGE_EXECUTE_READWRITE); assert(SMCPtr); int state = WriteProcessMemory(GetCurrentProcess(),SMCPtr,CriticalCodeSCSrcEnc,CriticalCodeLen,&writtenNum); assert(state); HMODULE hU32Mod = LoadLibrary("user32.dll"); HMODULE hKrlMod = LoadLibrary("kernel32.dll"); DeCodeSMC(SMCPtr,CriticalCodeLen); __asm { push SMCPtr; jmp [esp]; } }V5又是一个半成品,不说了,直接跳到V5-1
//v5-1 int main() { DWORD writtenNum=0; DWORD CriticalCodeLen = 0x50; //CriticalCodeSCSrcEnc将原CriticalCodeSCSrc中的与0xcc异或 生成新的编码 //运行前先与0xcc异或解密 char CriticalCodeSCSrcEnc[] = {"\x99\x47\x20\x4F\x20\xDC\x7C\x8F" \ "\x44\x89\x30\x7C\xAD\x44\x89\x31" \ "\x7C\xBC\x44\x89\x32\xFF\x0C\x44" \ "\x89\x33\x7C\x81\x44\x89\x34\x7C" \ "\xBF\x44\x89\x35\x7C\xAB\x44\x89" \ "\x36\xFF\x0C\x44\x89\x37\xA6\xCC" \ "\x41\x89\x30\x9C\x41\x89\x34\x9C" \ "\xA6\xCC\x74\xD2\x31\x56\xB8\x33" \ "\x1C\xA6\xCC\x74\x14\xB5\x43\xBA" \ "\x33\x1C\x00\x00\x00\x00\x00\x00"}; DWORD DeCodeSMCLen = 0x80; char DeCodeSMC[] = {"\x55\x8B\xEC\x83\xEC\x10\xC6\x45" \ "\xFC\x00\xC6\x45\xFD\x00\xC6\x45" \ "\xFE\x00\xC6\x45\xFF\x00\xEB\x07" \ "\x8B\x45\xFC\x40\x89\x45\xFC\x8B" \ "\x4D\xFC\x3B\x4D\x0C\x73\x14\x8B" \ "\x55\x08\x03\x55\xFC\x8A\x02\x34" \ "\xCC\x8B\x4D\x08\x03\x4D\xFC\x88" \ "\x01\xEB\xDD\x8B\xE5\x5D\xC2\x08" \ "\x00\xCC\xCC\xCC\xCC\xCC\xCC\xCC"}; char* SMCPtr = (char*)VirtualAllocEx(GetCurrentProcess(),NULL,0x1000,MEM_COMMIT,PAGE_EXECUTE_READWRITE); assert(SMCPtr); int state = WriteProcessMemory(GetCurrentProcess(),SMCPtr,CriticalCodeSCSrcEnc,CriticalCodeLen,&writtenNum); assert(state); char* SMCDecPtr = (char*)VirtualAllocEx(GetCurrentProcess(),NULL,0x1000,MEM_COMMIT,PAGE_EXECUTE_READWRITE); assert(SMCPtr); state = WriteProcessMemory(GetCurrentProcess(),SMCDecPtr,DeCodeSMC,DeCodeSMCLen,&writtenNum); assert(state); HMODULE hU32Mod = LoadLibrary("user32.dll"); HMODULE hKrlMod = LoadLibrary("kernel32.dll"); //程序中已经没有DeCodeSMC这个函数 但是进程地址空间中还有类似功能的二进制码 需要显式模拟一次DeCodeSMC调用 //DeCodeSMC(SMCPtr,CriticalCodeLen); __asm { //注意DeCodeSMC压栈顺序,右边的先入栈-先push push CriticalCodeLen push SMCPtr //模拟调用DeCodeSMC(SMCPtr,CriticalCodeLen); call SMCDecPtr } //SMC完成 跳去受保护的代码端执行 __asm { push SMCPtr; jmp [esp]; } }借助V5,将DeCodeSMC成功毁容,现在DeCodeSMC已经寄居在DeCodeSMC数组中,程序运行前跳转到DeCodeSMC数组中,解密CriticalCodeSCSrcEnc数组,解密完成才跳转到CriticalCodeSCSrcEnc执行。
写到这,隐藏的够深了吧?No,如果用调试器调试跟踪运行,一切还是白搭,因此下一步要检测调试器是否存在,如果存在,程序退出,麻烦你还是静态分析,因为静态分析已经够麻烦了。
//开始动态反调试前 看个检测调试器的函数 __declspec(naked) bool IsDebuggerPresent() { //windows设定 fs:[30]这个内存为当前进程的进程控制块 //进程控制块的第二个字节标志进程是否被调试 __asm { mov eax,fs:[0x30]; movzx eax,[eax+0x02]; ret; } }原本以为win7带有IsDebuggerPresent这API,结果么得,只能自己实现了。
好的,加上检测调试器:
//V6-1 解密前 检测是否动态调试
//V6-1 解密前 检测是否动态调试 int main() { DWORD writtenNum=0; DWORD CriticalCodeLen = 0x50; //CriticalCodeSCSrcEnc将原CriticalCodeSCSrc中的与0xcc异或 生成新的编码 //运行前先与0xcc异或解密 char CriticalCodeSCSrcEnc[] = {"\x99\x47\x20\x4F\x20\xDC\x7C\x8F" \ "\x44\x89\x30\x7C\xAD\x44\x89\x31" \ "\x7C\xBC\x44\x89\x32\xFF\x0C\x44" \ "\x89\x33\x7C\x81\x44\x89\x34\x7C" \ "\xBF\x44\x89\x35\x7C\xAB\x44\x89" \ "\x36\xFF\x0C\x44\x89\x37\xA6\xCC" \ "\x41\x89\x30\x9C\x41\x89\x34\x9C" \ "\xA6\xCC\x74\xD2\x31\x56\xB8\x33" \ "\x1C\xA6\xCC\x74\x14\xB5\x43\xBA" \ "\x33\x1C\x00\x00\x00\x00\x00\x00"}; DWORD DeCodeSMCLen = 0xC0; char DeCodeSMC[] = { "\x64\xA1\x30\x00\x00\x00\x0F\xB6" \ "\x40\x02\x83\xF8\x00\x74\x09\x6A" \ "\x00\xB8\xD8\x79\x8F\x76\xFF\xD0" \ "\x90\x90\x90\x90\x90\x90\x90\x90" \ "\x55\x8B\xEC\x83\xEC\x10\xC6\x45" \ "\xFC\x00\xC6\x45\xFD\x00\xC6\x45" \ "\xFE\x00\xC6\x45\xFF\x00\xEB\x07" \ "\x8B\x45\xFC\x40\x89\x45\xFC\x8B" \ "\x4D\xFC\x3B\x4D\x0C\x73\x14\x8B" \ "\x55\x08\x03\x55\xFC\x8A\x02\x34" \ "\xCC\x8B\x4D\x08\x03\x4D\xFC\x88" \ "\x01\xEB\xDD\x8B\xE5\x5D\xC2\x08" \ "\x00\xCC\xCC\xCC\xCC\xCC\xCC\xCC"}; char* SMCPtr = (char*)VirtualAllocEx(GetCurrentProcess(),NULL,0x1000,MEM_COMMIT,PAGE_EXECUTE_READWRITE); assert(SMCPtr); int state = WriteProcessMemory(GetCurrentProcess(),SMCPtr,CriticalCodeSCSrcEnc,CriticalCodeLen,&writtenNum); assert(state); char* SMCDecPtr = (char*)VirtualAllocEx(GetCurrentProcess(),NULL,0x1000,MEM_COMMIT,PAGE_EXECUTE_READWRITE); assert(SMCPtr); state = WriteProcessMemory(GetCurrentProcess(),SMCDecPtr,DeCodeSMC,DeCodeSMCLen,&writtenNum); assert(state); HMODULE hU32Mod = LoadLibrary("user32.dll"); HMODULE hKrlMod = LoadLibrary("kernel32.dll"); //程序中已经没有DeCodeSMC这个函数 但是进程地址空间中还有类似功能的二进制码 需要显式模拟一次DeCodeSMC调用 //DeCodeSMC(SMCPtr,CriticalCodeLen); __asm { //注意DeCodeSMC压栈顺序,右边的先入栈-先push push CriticalCodeLen push SMCPtr //模拟DeCodeSMC(SMCPtr,CriticalCodeLen); call SMCDecPtr } //SMC完成 跳去受保护的代码端执行 __asm { push SMCPtr; jmp [esp]; } }这段Shellcode在DeCodeSMC入口检测调试器,如果存在程序退出。现在可以试试程序直接运行和调试运行的结果。
解密函数反动态调试是过了,观察者还能静态分析,为了对付静态分析,我再手贱加点花指令,干扰他们静态分析,深入的花指令看我另一篇博文
__declspec(naked) void DeCodeSMC(char* SMCPtr,DWORD SMCLen) { __asm { //[ebp+0]:ebp [ebp+0x04]:retAddtr [ebp+0x08]:SMCPtr [ebp+0x0C]:SMCLen mov eax,fs:[0x30]; movzx eax,[eax+0x02]; cmp eax,0x00; jz StartDecode; push 0x00; mov eax,0x768F79D8; call eax; StartDecode: nop; nop; nop; nop; push ebp; mov ebp,esp; sub esp,0x10; //[ebp-4]:DWORD i; mov [ebp-4],0x00; mov [ebp-3],0x00; mov [ebp-2],0x00; mov [ebp-1],0x00; jmp Lab2; Lab1: //插入花指令 mov eax,0; cmp eax,1; jnz ThunkCode1; jz ThunkCode1; _emit 0xE9 ThunkCode1: //花指令结束 mov eax,[ebp-4]; inc eax; mov [ebp-4],eax Lab2: mov ecx,[ebp-4]; cmp ecx,[ebp+0Ch]; jae Lab3; //插入花指令 mov eax,1; cmp eax,0; jnz ThunkCode2; jz ThunkCode2; _emit 0xE9 ThunkCode2: //花指令结束 mov edx,[ebp+8]; add edx,[ebp-4]; mov al,[edx]; xor al,0xCC; mov ecx,[ebp+8]; add ecx,[ebp-4]; mov [ecx],al; jmp Lab1; Lab3: mov esp,ebp; pop ebp; ret 8 } } int main() { DWORD writtenNum=0; DWORD CriticalCodeLen = 0x50; //CriticalCodeSCSrcEnc将原CriticalCodeSCSrc中的与0xcc异或 生成新的编码 //运行前先与0xcc异或解密 char CriticalCodeSCSrcEnc[] = {"\x99\x47\x20\x4F\x20\xDC\x7C\x8F" \ "\x44\x89\x30\x7C\xAD\x44\x89\x31" \ "\x7C\xBC\x44\x89\x32\xFF\x0C\x44" \ "\x89\x33\x7C\x81\x44\x89\x34\x7C" \ "\xBF\x44\x89\x35\x7C\xAB\x44\x89" \ "\x36\xFF\x0C\x44\x89\x37\xA6\xCC" \ "\x41\x89\x30\x9C\x41\x89\x34\x9C" \ "\xA6\xCC\x74\xD2\x31\x56\xB8\x33" \ "\x1C\xA6\xCC\x74\x14\xB5\x43\xBA" \ "\x33\x1C\x00\x00\x00\x00\x00\x00"}; char* SMCPtr = (char*)VirtualAllocEx(GetCurrentProcess(),NULL,0x1000,MEM_COMMIT,PAGE_EXECUTE_READWRITE); assert(SMCPtr); int state = WriteProcessMemory(GetCurrentProcess(),SMCPtr,CriticalCodeSCSrcEnc,CriticalCodeLen,&writtenNum); assert(state); HMODULE hU32Mod = LoadLibrary("user32.dll"); HMODULE hKrlMod = LoadLibrary("kernel32.dll"); DeCodeSMC(SMCPtr,CriticalCodeLen); __asm { push SMCPtr; jmp [esp]; } }这个也是过渡版,来看下大结局
int main() { DWORD writtenNum=0; DWORD CriticalCodeLen = 0x50; //CriticalCodeSCSrcEnc将原CriticalCodeSCSrc中的与0xcc异或 生成新的编码 //运行前先与0xcc异或解密 char CriticalCodeSCSrcEnc[] = {"\x99\x47\x20\x4F\x20\xDC\x7C\x8F" \ "\x44\x89\x30\x7C\xAD\x44\x89\x31" \ "\x7C\xBC\x44\x89\x32\xFF\x0C\x44" \ "\x89\x33\x7C\x81\x44\x89\x34\x7C" \ "\xBF\x44\x89\x35\x7C\xAB\x44\x89" \ "\x36\xFF\x0C\x44\x89\x37\xA6\xCC" \ "\x41\x89\x30\x9C\x41\x89\x34\x9C" \ "\xA6\xCC\x74\xD2\x31\x56\xB8\x33" \ "\x1C\xA6\xCC\x74\x14\xB5\x43\xBA" \ "\x33\x1C\x00\x00\x00\x00\x00\x00"}; DWORD DeCodeSMCLen = 0x110; char DeCodeSMC[] = { "\x64\xA1\x30\x00\x00\x00\x0F\xB6" \ "\x40\x02\x83\xF8\x00\x74\x09\x6A" \ "\x00\xB8\xD8\x79\x8F\x76\xFF\xD0" \ "\x90\x90\x90\x90\x55\x8B\xEC\x83" \ "\xEC\x10\xC6\x45\xFC\x00\xC6\x45" \ "\xFD\x00\xC6\x45\xFE\x00\xC6\x45" \ "\xFF\x00\xEB\x14\xB8\x00\x00\x00" \ "\x00\x83\xF8\x01\x75\x03\x74\x01" \ "\xE9\x8B\x45\xFC\x40\x89\x45\xFC" \ "\x8B\x4D\xFC\x3B\x4D\x0C\x73\x21" \ "\xB8\x01\x00\x00\x00\x83\xF8\x00" \ "\x75\x03\x74\x01\xE9\x8B\x55\x08" \ "\x03\x55\xFC\x8A\x02\x34\xCC\x8B" \ "\x4D\x08\x03\x4D\xFC\x88\x01\xEB" \ "\xC3\x8B\xE5\x5D\xC2\x08\x00\xCC" \ "\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC"}; char* SMCPtr = (char*)VirtualAllocEx(GetCurrentProcess(),NULL,0x1000,MEM_COMMIT,PAGE_EXECUTE_READWRITE); assert(SMCPtr); int state = WriteProcessMemory(GetCurrentProcess(),SMCPtr,CriticalCodeSCSrcEnc,CriticalCodeLen,&writtenNum); assert(state); char* SMCDecPtr = (char*)VirtualAllocEx(GetCurrentProcess(),NULL,0x1000,MEM_COMMIT,PAGE_EXECUTE_READWRITE); assert(SMCPtr); state = WriteProcessMemory(GetCurrentProcess(),SMCDecPtr,DeCodeSMC,DeCodeSMCLen,&writtenNum); assert(state); HMODULE hU32Mod = LoadLibrary("user32.dll"); HMODULE hKrlMod = LoadLibrary("kernel32.dll"); //程序中已经没有DeCodeSMC这个函数 但是进程地址空间中还有类似功能的二进制码 需要显式模拟一次DeCodeSMC调用 //DeCodeSMC(SMCPtr,CriticalCodeLen); __asm { //注意DeCodeSMC压栈顺序,右边的先入栈-先push push CriticalCodeLen push SMCPtr //模拟DeCodeSMC(SMCPtr,CriticalCodeLen); call SMCDecPtr } //SMC完成 跳去受保护的代码端执行 __asm { push SMCPtr; jmp [esp]; } }经手术函数CriticalCodeV1已成功整容,不用几天我也记不得他原本长什么样~
int main() { DWORD writtenNum=0; DWORD CriticalCodeLen = 0x50; //CriticalCodeSCSrcEnc将原CriticalCodeSCSrc中的与0xcc异或 生成新的编码 //运行前先与0xcc异或解密 char CriticalCodeSCSrcEnc[] = {"\x99\x47\x20\x4F\x20\xDC\x7C\x8F" \ "\x44\x89\x30\x7C\xAD\x44\x89\x31" \ "\x7C\xBC\x44\x89\x32\xFF\x0C\x44" \ "\x89\x33\x7C\x81\x44\x89\x34\x7C" \ "\xBF\x44\x89\x35\x7C\xAB\x44\x89" \ "\x36\xFF\x0C\x44\x89\x37\xA6\xCC" \ "\x41\x89\x30\x9C\x41\x89\x34\x9C" \ "\xA6\xCC\x74\xD2\x31\x56\xB8\x33" \ "\x1C\xA6\xCC\x74\x14\xB5\x43\xBA" \ "\x33\x1C\x00\x00\x00\x00\x00\x00"}; DWORD DeCodeSMCLen = 0x110; char DeCodeSMC[] = { "\x64\xA1\x30\x00\x00\x00\x0F\xB6" \ "\x40\x02\x83\xF8\x00\x74\x09\x6A" \ "\x00\xB8\xD8\x79\x8F\x76\xFF\xD0" \ "\x90\x90\x90\x90\x55\x8B\xEC\x83" \ "\xEC\x10\xC6\x45\xFC\x00\xC6\x45" \ "\xFD\x00\xC6\x45\xFE\x00\xC6\x45" \ "\xFF\x00\xEB\x14\xB8\x00\x00\x00" \ "\x00\x83\xF8\x01\x75\x03\x74\x01" \ "\xE9\x8B\x45\xFC\x40\x89\x45\xFC" \ "\x8B\x4D\xFC\x3B\x4D\x0C\x73\x21" \ "\xB8\x01\x00\x00\x00\x83\xF8\x00" \ "\x75\x03\x74\x01\xE9\x8B\x55\x08" \ "\x03\x55\xFC\x8A\x02\x34\xCC\x8B" \ "\x4D\x08\x03\x4D\xFC\x88\x01\xEB" \ "\xC3\x8B\xE5\x5D\xC2\x08\x00\xCC" \ "\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC"}; char* SMCPtr = (char*)VirtualAllocEx(GetCurrentProcess(),NULL,0x1000,MEM_COMMIT,PAGE_EXECUTE_READWRITE); assert(SMCPtr); int state = WriteProcessMemory(GetCurrentProcess(),SMCPtr,CriticalCodeSCSrcEnc,CriticalCodeLen,&writtenNum); assert(state); char* SMCDecPtr = (char*)VirtualAllocEx(GetCurrentProcess(),NULL,0x1000,MEM_COMMIT,PAGE_EXECUTE_READWRITE); assert(SMCPtr); state = WriteProcessMemory(GetCurrentProcess(),SMCDecPtr,DeCodeSMC,DeCodeSMCLen,&writtenNum); assert(state); HMODULE hU32Mod = LoadLibrary("user32.dll"); HMODULE hKrlMod = LoadLibrary("kernel32.dll"); //程序中已经没有DeCodeSMC这个函数 但是进程地址空间中还有类似功能的二进制码 需要显式模拟一次DeCodeSMC调用 //DeCodeSMC(SMCPtr,CriticalCodeLen); __asm { //注意DeCodeSMC压栈顺序,右边的先入栈-先push push CriticalCodeLen push SMCPtr //模拟DeCodeSMC(SMCPtr,CriticalCodeLen); call SMCDecPtr } //SMC完成 跳去受保护的代码端执行 __asm { push SMCPtr; jmp [esp]; } }