windows 加壳工具代码实现04 - 壳代码的载体Stub.dll 目录Stub.dll添加一个动态链接库项目以及配置新建头文件新建一个源文件源文件包含头文件环境配置代码设置(区段设置)stub.h 头文件设置全局结构Kernel32等函数(stub.cpp)start入口函数(Stub.cpp)生成DLL放入到加壳器的位置Stub.dll作用由 Stub.cpp 编译生成的动态链接库。干嘛的不是给用户直接运行的而是被Pack.cpp在加壳过程中加载并提取其代码。Pack 函数会把 Stub.dll 的 .text 段内容整个复制出来附加到被加壳的 exe 文件的新区段中。最终用户加壳后的程序里包含的就是从这个 DLL 里扣出来的壳代码。地位壳代码的载体供加壳器“偷”代码用的模板。壳代码是如何写的我们可以写成动态链接库然后把代码扣出来然后写成一个新的区段写道目标程序添加一个动态链接库项目以及配置新建头文件新建一个源文件源文件包含头文件环境配置项目要写的是x64Release,因为这样方便扣代码其实相当于就是把壳代码当成shellcode代码来写然后丢入到目标区段里面我们现在的shellcode本质上就是一个shellcode代码设置(区段设置)代码段和数据段写在同一个段里面这里的目标也就是减少段 为增加壳代码段做好准备stub.h 头文件设置全局结构声明全局结构声明获取函数原型函数指针#pragma once #include Windows.h extern C { typedef struct _GLOBAL_PARAM { //壳里面的OEP DWORD dwStart; //镜像基址 ULONGLONG ullImageBase; //程序的OEP DWORD dwOEP; //被加密区域的起始位置 PBYTE lpStartVA; //被加密区域的尺寸 DWORD dwCodeSize; //异或加密用的加密Key BYTE byXorCode; }GLOBAL_PARAM,*PGLOBAL_PARAM; } // 获取函数原型函数指针 EXTERN_C typedef HMODULE (WINAPI * fnLoadLibraryA)(_In_ LPCSTR lpLibFileName); EXTERN_C typedef FARPROC (WINAPI * fnGetProcAddress)(_In_ HMODULE hModule,_In_ LPCSTR lpProcName); EXTERN_C typedef int (WINAPI * fnMessageBoxA)( _In_opt_ HWND hWnd, _In_opt_ LPCSTR lpText, _In_opt_ LPCSTR lpCaption, _In_ UINT uType); EXTERN_C typedef VOID (WINAPI * fnExitProcess)(_In_ UINT uExitCode); EXTERN_C typedef HMODULE (WINAPI * fnGetModuleHandleA)(_In_opt_ LPCSTR lpModuleName); EXTERN_C typedef BOOL(WINAPI *fnVirtualProtect)(_In_ LPVOID lpAddress, _In_ SIZE_T dwSize, _In_ DWORD flNewProtect, _Out_ PDWORD lpflOldProtect); EXTERN_C void Start();Kernel32等函数(stub.cpp)ULONGLONG GetKernel32Address() { ULONGLONG dwKernel32 0; _TEB* pTeb NtCurrentTeb(); PULONGLONG pPeb (PULONGLONG) * (PULONGLONG)((ULONGLONG)pTeb 0x60); PULONGLONG pLdr (PULONGLONG) * (PULONGLONG)((ULONGLONG)pPeb 0x18); PULONGLONG InLoadOrderModuleList (PULONGLONG)((ULONGLONG)pLdr 0x10); PULONGLONG pModuleExe (PULONGLONG)*InLoadOrderModuleList; PULONGLONG pModuleNtdll (PULONGLONG)*pModuleExe; PULONGLONG pModuleKernel32 (PULONGLONG)*pModuleNtdll; dwKernel32 pModuleKernel32[6]; return dwKernel32; } ULONGLONG GrkGetProcessAddress() { ULONGLONG dwBase GetKernel32Address(); PIMAGE_DOS_HEADER pDos (PIMAGE_DOS_HEADER)dwBase; PIMAGE_NT_HEADERS pNt (PIMAGE_NT_HEADERS)(pDos-e_lfanew dwBase); PIMAGE_DATA_DIRECTORY pExportDir pNt-OptionalHeader.DataDirectory; pExportDir (pExportDir[IMAGE_DIRECTORY_ENTRY_EXPORT]); DWORD dwOffset pExportDir-VirtualAddress; PIMAGE_EXPORT_DIRECTORY pExport (PIMAGE_EXPORT_DIRECTORY)(dwBase dwOffset); DWORD dwFuncCount pExport-NumberOfFunctions; DWORD dwFuncNameCount pExport-NumberOfNames; DWORD dwModOffset pExport-Name; PDWORD pEAT (PDWORD)(dwBase pExport-AddressOfFunctions); PDWORD pENT (PDWORD)(dwBase pExport-AddressOfNames); PWORD pEIT (PWORD)(dwBase pExport-AddressOfNameOrdinals); for (size_t i 0; i dwFuncCount; i) { if (!pEAT[i]) { continue; } DWORD dwOrdinal pExport-Base i; ULONGLONG dwFunAddrOffset pEAT[i]; for (size_t index 0; index dwFuncNameCount; index) { if (pEIT[index] i) { ULONGLONG dwNameOffset pENT[index]; char* szFuncName (char*)(((ULONGLONG)dwBase) dwNameOffset); if (strcmp(szFuncName, GetProcAddress) 0) { return dwBase dwFunAddrOffset; } } } } } void XorCode() { PBYTE pBase (PBYTE)((ULONGLONG)g_stcParam.ullImageBase g_stcParam.lpStartVA); for (size_t i 0; i g_stcParam.dwCodeSize; i) { pBase[i] ^ g_stcParam.byXorCode; } }start入口函数(Stub.cpp)void Start() { //这段代码的功能是**动态解析Dynamic Resolution**一系列关键的 Windows API 函数地址。 fnGetProcAddress pfnGetProcAddress (fnGetProcAddress)GrkGetProcessAddress(); ULONGLONG ullKernelBase GetKernel32Address(); fnLoadLibraryA pfnLoadLibraryA (fnLoadLibraryA)pfnGetProcAddress((HMODULE)ullKernelBase, LoadLibraryA); //获取对应函数原因 以及User32.dll地址 HMODULE hUesr32 pfnLoadLibraryA(user32.dll); fnVirtualProtect pfnVirtualProtect (fnVirtualProtect)pfnGetProcAddress((HMODULE)ullKernelBase, VirtualProtect); fnGetModuleHandleA pfnGetModuleHandleA (fnGetModuleHandleA)pfnGetProcAddress((HMODULE)ullKernelBase, GetModuleHandleA); fnMessageBoxA pfnMessageBoxA (fnMessageBoxA)pfnGetProcAddress(hUesr32, MessageBoxA); fnExitProcess pfnExitProcess (fnExitProcess)pfnGetProcAddress((HMODULE)ullKernelBase, ExitProcess); //调用函数 int nRetCode pfnMessageBoxA(NULL, 是否解密打开原有程序, Msg, MB_YESNO); // ------- 判断是否解密成功 if (nRetCode IDYES) { ULONGLONG ullCodeBase g_stcParam.ullImageBase (ULONGLONG)g_stcParam.lpStartVA; //获取代码段基地址 ImageBase 代码区段RVA DWORD dwOldPrtect 0;//修改属性 修改了属性才能进行写操作 pfnVirtualProtect((LPBYTE)ullCodeBase, g_stcParam.dwCodeSize, PAGE_EXECUTE_READWRITE, dwOldPrtect); XorCode(); //解密操作 pfnVirtualProtect((LPBYTE)ullCodeBase, g_stcParam.dwCodeSize, dwOldPrtect, dwOldPrtect); g_Oep (JUMPOEP)(g_stcParam.ullImageBase g_stcParam.dwOEP); //函数指针赋值 跳回到原始代码段的程序入口点 g_Oep(); } pfnExitProcess(0); }这个区段是作为一个验证以及跳回的操作整体功能解释这段代码的核心目标是找到kernel32.dll的基地址。找到GetProcAddress或其自定义实现的地址。利用找到的GetProcAddress动态获取其他核心函数如LoadLibraryA,VirtualProtect,ExitProcess的地址。使用动态获取的LoadLibraryA加载user32.dll。从user32.dll中获取MessageBoxA的地址。完成这些步骤后程序就可以通过这些函数指针pfnLoadLibraryA,pfnMessageBoxA等来调用相应的 Windows API。生成DLL放入到加壳器的位置和加壳器代码放在一起