-
-
[讨论]windows x64下的pic-shellcode
-
发表于: 2025-6-5 13:39 320
-
windows下的pic-shellcode可以通过遍历模块表实现,代码如下
void __declspec(noinline) newShellcode(void) {
//通过peb的ldr表获取模块表
Peb* peb;
__asm {
mov rax, gs:[30h]
mov rdx, [rax+60h]
mov peb, rdx
}
PebLdrData* ldr = (PebLdrData*)peb->Ldr;
_LIST_ENTRY* ModuleList = &(ldr->InLoadOrderModuleList);
_LIST_ENTRY* next = ModuleList->Flink;
FARPROC(*pGetProcAddr)(HMODULE, LPCSTR) = NULL;
HMODULE(*pLoadLibrary)(LPCSTR) = NULL;
while (next != ModuleList)
//遍历模块表,寻找kernel32.dll模块在表中的对应项
{
_UNICODE_STRING BaseDllName = ((LdrTableEntry*)next)->BaseDllName;
WCHAR* buffer = BaseDllName.Buffer;
WCHAR KER32[13];
*((ULONG64*)KER32) = 0x4e00520045004b;
*((ULONG64*)KER32 + 1) = 0x320033004c0045;
*((ULONG64*)KER32 + 2) = 0x4c004c0044002e;
KER32[12] = 0;
CHAR GetProcAddr[15];
*((ULONG64*)GetProcAddr) = 0x41636f7250746547;
*((DWORD*)GetProcAddr + 2) = 0x65726464;
*((WORD*)GetProcAddr + 6) = 0x7373;
GetProcAddr[14] = 0;
CHAR LoadLib[13];
*((ULONG64*)LoadLib) = 0x7262694c64616f4c;
*((DWORD*)LoadLib + 2) = 0x41797261;
LoadLib[12] = 0;
int i;
for (i = 0; buffer[i] || KER32[i]; i++)
if (buffer[i] != KER32[i])
break;
if (buffer[i] != KER32[i])
{
next = next->Flink;
continue;
}
//找到kernel32.dll后,根据dll头寻找其导出表以及其上所有数据
LPVOID DllBase = (LPVOID)(((LdrTableEntry*)next)->DllBase);
_IMAGE_DOS_HEADER* DosHeader = (_IMAGE_DOS_HEADER*)(((LdrTableEntry*)next)->DllBase);
_IMAGE_NT_HEADERS64* NTHeader = (_IMAGE_NT_HEADERS64*)((ULONG64)DosHeader + (ULONG64)(DosHeader->e_lfanew));
_IMAGE_EXPORT_DIRECTORY* ExportDirectory = (_IMAGE_EXPORT_DIRECTORY*)((ULONG64)DllBase +
NTHeader->OptionalHeader.DataDirectory[0].VirtualAddress);
DWORD* AddressOfFunctions = (DWORD*)((ULONG64)DllBase + (ULONG64)(ExportDirectory->AddressOfFunctions));
DWORD* AddressOfNames = (DWORD*)((ULONG64)DllBase + (ULONG64)(ExportDirectory->AddressOfNames));
WORD* AddressOfNameOridinals = (WORD*)((ULONG64)DllBase + (ULONG64)(ExportDirectory->AddressOfNameOrdinals));
DWORD NumberOfNames = ExportDirectory->NumberOfNames;
//根据导出表的NumberOfNames子表,寻找GetProcAddress和LoadLibrary
for (i = 0; i < NumberOfNames; i++) {
int j = 0;
//GetProcAddress
if (pGetProcAddr == NULL) {
//遍历AddressOfNames表的每一项,与字符串GetProcAddr对比
for (; ((CHAR*)(AddressOfNames[i] + (ULONG64)DllBase))[j] || GetProcAddr[j]; j++)
if (((CHAR*)(AddressOfNames[i] + (ULONG64)DllBase))[j] != GetProcAddr[j])
break;
//导出函数偏移量在偏移量表的位置为函数名在名字表的下标所对应的序号表中的序号
if (((CHAR*)(AddressOfNames[i] + (ULONG64)DllBase))[j] == GetProcAddr[j])
pGetProcAddr = (FARPROC(*)(HMODULE, LPCSTR))((ULONG64)DllBase + (ULONG64)AddressOfFunctions[AddressOfNameOridinals[i]]);
}
//LoadLibrary
else if (pLoadLibrary == NULL) {
//寻找LoadLibrary函数的过程与GetProcAddress的类似
for (j = 0; ((CHAR*)(AddressOfNames[i] + (ULONG64)DllBase))[j] || LoadLib[j]; j++)
if (((CHAR*)(AddressOfNames[i] + (ULONG64)DllBase))[j] != LoadLib[j])
break;
if (((CHAR*)(AddressOfNames[i] + (ULONG64)DllBase))[j] == LoadLib[j])
pLoadLibrary = (HMODULE(*)(LPCSTR))((ULONG64)DllBase + (ULONG64)AddressOfFunctions[AddressOfNameOridinals[i]]);
}
//两个函数均已找到,退出循环
else
break;
}
break;
}
/*找到两个函数后,就可以用对应指针调用,编译后作为shellcode*/
// code here ...
}需要使用llvm或者mingw进行编译,因为用到了内联汇编
[培训]Windows内核深度攻防:从Hook技术到Rootkit实战!
赞赏
他的文章
赞赏
雪币:
留言: