首页
社区
课程
招聘
[讨论]windows x64下的pic-shellcode
发表于: 2025-6-5 13:39 145

[讨论]windows x64下的pic-shellcode

2025-6-5 13:39
145

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进行编译,因为用到了内联汇编


[培训]科锐逆向工程师培训第53期2025年7月8日开班!

收藏
免费 0
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回