zoukankan      html  css  js  c++  java
  • 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
    ");
            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 "); 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; }

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

    注入后

    运行

  • 相关阅读:
    C++ 并发编程 01 线程api
    C# CS1591 缺少对公共可见类型或成员的 XML 注释 问题解决
    Web Api HelpPage
    C++11新特性介绍 02
    C++11新特性介绍 01
    Autofac框架详解
    Linux gdb调试器用法全面解析
    BCM_SDK命令
    VLAN
    java_Observer Design Pattern
  • 原文地址:https://www.cnblogs.com/harmonica11/p/13848627.html
Copyright © 2011-2022 走看看