PE学习:导入表注入

最近深感自己基础不牢,回头学了一遍PE,顺手做了个导入表注入的小练习

首先准备一个DLL用来测试

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        init();
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}
void init() {
    MessageBoxA(0, "Success", "Test", MB_OK);
}

int plus(int a, int b) {
    return a + b;
}

再准备一个exe

.386
.MODEL flat,stdcall
option casemap:none

include        windows.inc
include        gdi32.inc
includelib    gdi32.lib
include        user32.inc
includelib    user32.lib
include        kernel32.inc
includelib    kernel32.lib

.data?
hInstance    dd    ?
hWinMain    dd    ?

.const        
szClassName        db    'Myclass',0
szCaptionMain    db    'My first window',0
szText            db  'win32 Assembly,simple and powerful !',0
szButton        db    'button',0
szButtonText    db    '&ok',0

.code

_ProcWinMain    proc    uses ebx edi esi,hWnd,uMsg,wParam,lParam
    local    @stPs:PAINTSTRUCT
    local    @stRect:RECT
    local    @hDc

    mov        eax,uMsg
    .if        eax == WM_PAINT
            invoke    BeginPaint,hWnd,addr @stPs
            mov        @hDc,eax
            invoke    GetClientRect,hWnd,addr @stRect
            invoke    DrawText,@hDc,addr szText,-1,addr @stRect,DT_SINGLELINE or DT_CENTER or DT_VCENTER
            invoke    EndPaint,hWnd,addr @stPs

    .elseif    eax == WM_CLOSE
            invoke    DestroyWindow,hWinMain
            invoke    PostQuitMessage,NULL

    .else
            invoke    DefWindowProc,hWnd,uMsg,wParam,lParam
            ret

    .endif
    xor        eax,eax
    ret

_ProcWinMain    endp

_WinMain    proc
    local    @stWndClass:WNDCLASSEX
    local    @stMsg:MSG

    invoke    GetModuleHandle,NULL
    mov        hInstance,eax
    invoke    RtlZeroMemory,addr @stWndClass,sizeof @stWndClass

    invoke    LoadCursor,0,IDC_ARROW
    mov        @stWndClass.hCursor,eax
    push    hInstance
    pop        @stWndClass.hInstance
    mov        @stWndClass.cbSize,sizeof WNDCLASSEX
    mov        @stWndClass.style,CS_HREDRAW or CS_VREDRAW
    mov        @stWndClass.lpfnWndProc,offset _ProcWinMain
    mov        @stWndClass.hbrBackground,COLOR_WINDOW + 1
    mov        @stWndClass.lpszClassName,offset szClassName
    invoke    RegisterClassEx,addr @stWndClass

    invoke    CreateWindowEx,WS_EX_CLIENTEDGE,offset szClassName,offset szCaptionMain,\
            WS_OVERLAPPEDWINDOW,100,100,600,400,NULL,NULL,hInstance,NULL
    mov        hWinMain,eax
    invoke    ShowWindow,hWinMain,SW_SHOWNORMAL
    invoke    UpdateWindow,hWinMain

    .while    TRUE
        invoke    GetMessage,addr @stMsg,NULL,0,0
        .break    .if    eax == 0
        invoke    TranslateMessage,addr @stMsg
        invoke    DispatchMessage,addr @stMsg
    .endw
    ret

_WinMain    endp

start:
    call    _WinMain
    invoke    ExitProcess,NULL

end    start

运行效果

 

要完成导入表注入,需要以下几步

1    打开一个exe
2    新增一个节
3    把导入表移进去
4    写入自己的导入表
5    存盘

关于导入表的资料网上有很多我就不细说了,这里主要就放一下代码,这个代码我写的很随意,看着应该比较丑hhhhh

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

FILE* fp = fopen(fileName, "rb");
    if (fp == NULL) {
        printf("open failed\n");
        exit(0);
    }
    fseek(fp, 0, SEEK_END);
    unsigned int len = ftell(fp);
    fseek(fp, 0, SEEK_SET);
    char* buf = (char*)malloc(2 * len);//因为exe要扩充,所以这里直接扩了一倍,简单暴力hhh
    if (buf != NULL) {
        memset(buf, '\x00', 2 * len);
        fread(buf, len, 1, fp);
    }
    fclose(fp);
    char* lpnewSec = buf + newSection(buf);//指向新增的节
    inject(buf, lpnewSec, fileName);
    free(buf);
    buf = NULL;

新增节:

unsigned __int32 newSection(char* buf) {
    unsigned __int32 e_lfanew = *(unsigned __int32*)(buf + 0x3c);
    char* FIheader = buf + e_lfanew + 4;
    char* OPheader = FIheader+0x14;
//扩大地址,我直接加了一个内存对齐的大小 unsigned __int32 SectionAlignment
= *(unsigned __int32*)(OPheader + 0x20); unsigned __int32 SizeOfImage = *(unsigned __int32*)(OPheader + 0x38); *(unsigned __int32*)(buf + 0x38 + (e_lfanew + 0x18)) = SizeOfImage + SectionAlignment; SizeOfImage = *(unsigned __int32*)(OPheader + 0x38); unsigned __int32 SizeoOfHeaders = *(unsigned __int32*)(OPheader + 0x3c); unsigned __int16 NumberOfSections = *(unsigned __int16*)(FIheader + 0x2); __int16 SizeOfOptionalHeader = *(unsigned __int16*)(FIheader + 0x10); char* Sections_addr = OPheader + SizeOfOptionalHeader;
//遍历节表 unsigned __int32 Misc
= 0; unsigned __int32 VirtualAddress = 0; unsigned __int32 SizeOfRawData = 0; unsigned __int32 PointerToRawData = 0; unsigned __int32 Characteristics = 0; for (int j = 0; j < NumberOfSections; j++) { Misc = *(unsigned __int32*)(Sections_addr + 0x8); VirtualAddress = *(unsigned __int32*)(Sections_addr + 0xc); SizeOfRawData = *(unsigned __int32*)(Sections_addr + 0x10); PointerToRawData = *(unsigned __int32*)(Sections_addr + 0x14); Characteristics |= *(unsigned __int32*)(Sections_addr + 0x24); Sections_addr = Sections_addr + 0x28; } unsigned int check = SizeoOfHeaders - (Sections_addr - buf); //当节表与第一个节的距离小于0x50时不能加节表,可以通过合并节等方式处理,这里没管
  
if (check < 0x50) { printf("can't add new Section"); exit(0); } *(unsigned __int16*)(FIheader + 0x2) += 1;//节表长度加一
//加入新节表 unsigned __int32 newSec_addr
= VirtualAddress + SectionAlignment; unsigned __int32 newSec_PointerToRawData = PointerToRawData + SizeOfRawData; *(unsigned __int64*)Sections_addr = 0x000000006362612e;//节名我直接取abc了 *(unsigned __int32*)(Sections_addr + 0x8) = SectionAlignment; *(unsigned __int32*)(Sections_addr + 0xc) = newSec_addr; *(unsigned __int32*)(Sections_addr + 0x10) = SectionAlignment; *(unsigned __int32*)(Sections_addr + 0x14) = newSec_PointerToRawData; *(unsigned __int32*)(Sections_addr + 0x24) = Characteristics; return newSec_PointerToRawData; }

注入

void inject(char* buf, char* newSec,const char* fileName) {
    unsigned __int32 e_lfanew = *(unsigned __int32*)(buf + 0x3c);
    char* FIheader = buf + e_lfanew + 4;
    char* OPheader = FIheader + 0x14;
    unsigned __int16 NumberOfSections = *(unsigned __int16*)(FIheader + 0x2);
    __int16 SizeOfOptionalHeader = *(unsigned __int16*)(FIheader + 0x10);

    char* Sections_addr = OPheader + SizeOfOptionalHeader;
    unsigned __int32 VirtualAddress = 0;
    unsigned __int32 SizeOfRawData = 0;
    unsigned __int32 PointerToRawData = 0;
    for (int j = 0; j < NumberOfSections; j++) {
        VirtualAddress = *(unsigned __int32*)(Sections_addr + 0xc);
        SizeOfRawData = *(unsigned __int32*)(Sections_addr + 0x10);
        PointerToRawData = *(unsigned __int32*)(Sections_addr + 0x14);
        Sections_addr = Sections_addr + 0x28;
    }

    char* lpDirectory = OPheader + SizeOfOptionalHeader - 0x80;
    unsigned __int32 ImportRVA = *(unsigned __int32*)(lpDirectory + 0x8);
    *(unsigned __int32*)(lpDirectory + 0x8) = VirtualAddress;
    unsigned __int32 ImportFOA = RVA_to_FOA(buf, ImportRVA);
    char* importAddr = buf + ImportFOA;
    char* newImport = newSec;
    unsigned __int32 count = 0;
//移动导入表,没有动INT和IAT
    while (*(unsigned __int32*)importAddr || *(unsigned __int32*)(importAddr + 0x4) || *(unsigned __int32*)(importAddr + 0x8) || *(unsigned __int32*)(importAddr + 0xc) || *(unsigned __int32*)(importAddr + 0x4)) {
        for (unsigned __int32 i = 0; i < 0x14; i++) {
            *(newImport + i) = *(importAddr + i);
        }
        count += 0x14;
        newImport += 0x14;
        importAddr += 0x14;
    }
    //new import
    *(unsigned __int32*)(newImport + 0x0) = VirtualAddress + count + 0x14;//指向新的INT
    *(unsigned __int32*)(newImport + 0x4) = 0;
    *(unsigned __int32*)(newImport + 0x8) = 0;
    *(unsigned __int32*)(newImport + 0xc) = VirtualAddress + count + 0x2b;//指向注入的DLL名
    *(unsigned __int32*)(newImport + 0x10) = VirtualAddress + count + 0x1c;//指向IAT
    //INT
    *(unsigned __int32*)(newImport + 0x14) = VirtualAddress + count + 0x24;//指向导入函数名,下面IAT也指向此处
    *(unsigned __int32*)(newImport + 0x18) = 0;
    //IAT
    *(unsigned __int32*)(newImport + 0x1c) = VirtualAddress + count + 0x24;
    *(unsigned __int32*)(newImport + 0x20) = 0;
//这里必须要有导入的函数,否则不会加载dll
*(unsigned __int16*)(newImport + 0x24) = 0; *(unsigned __int32*)(newImport + 0x26) = 0x73756c70;//plus *(newImport + 0x2a) = (char)0; //dLL name:testDLL.dll *(unsigned __int32*)(newImport + 0x2b) = 0x74736574; *(unsigned __int32*)(newImport + 0x2f) = 0x2e6c6c44; *(unsigned __int32*)(newImport + 0x33) = 0x006c6c64; FILE* fp = fopen(fileName, "wb"); if (fp == NULL) { printf("open failed\n"); exit(0); } fwrite(buf, SizeOfRawData + PointerToRawData, 1, fp); fclose(fp); }

RVA转为FOA

unsigned __int32 RVA_to_FOA(char* buf, unsigned __int32 RVA) {
    unsigned __int32 e_lfanew = *(unsigned __int32*)(buf + 0x3c);
    unsigned __int32 SizeoOfHeaders = *(unsigned __int32*)(buf + 0x3c + (e_lfanew + 0x18));
    unsigned __int32 FOA = 0;
//在文件头中不拉伸
if (RVA <= SizeoOfHeaders) { FOA = RVA; return FOA; } unsigned __int16 NumberOfSections = *(unsigned __int16*)(buf + e_lfanew + 0x4 + 0x2); __int16 SizeOfOptionalHeader = *(unsigned __int16*)(buf + e_lfanew + 0x4 + 0x10); char* Sections_addr = buf + e_lfanew + 0x18 + SizeOfOptionalHeader; //遍历节表判断在那个节中,FOA=RVA-节的RVA+节的FOA unsigned __int32 VirtualAddress = *(unsigned __int32*)(Sections_addr + 0xc); unsigned __int32 PointerToRawData = *(unsigned __int32*)(Sections_addr + 0x14); unsigned __int32 PrevVirtualAddress = *(unsigned __int32*)(Sections_addr + 0xc); unsigned __int32 PrevPointerToRawData = *(unsigned __int32*)(Sections_addr + 0x14); Sections_addr = Sections_addr + 0x28; for (int j = 0; j < NumberOfSections - 1; j++) { VirtualAddress = *(unsigned __int32*)(Sections_addr + 0xc); PointerToRawData = *(unsigned __int32*)(Sections_addr + 0x14); if (PrevVirtualAddress <= RVA && VirtualAddress > RVA) { FOA = PrevPointerToRawData + (RVA - PrevVirtualAddress); return FOA; } PrevVirtualAddress = VirtualAddress; PrevPointerToRawData = PointerToRawData; Sections_addr = Sections_addr + 0x28; } FOA = PrevPointerToRawData + (RVA - PrevVirtualAddress); return FOA; }

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

注入后

 

运行

 

posted @ 2020-10-20 20:20  Harmonica11  阅读(376)  评论(0编辑  收藏  举报