4月5日,學習shellcode,用peb找函數地址

來源:互聯網
上載者:User

雖然最後事情的結果很鬱悶,但中間的過程還是有些收穫的,
在編shellcode的時候,很重要的就是要找到要用的函數在記憶體中的位置,網上有很多寫好的模板,方法就

是通過peb和SEH找,找到的模板是用peb的。
主要目的就是找到kernel.dll在記憶體中的位置,進而找到GetProcAddress()的位置,有了這兩個,就可以

有LoAdLibrAry(),然後其他的函數地址問題就都解決了

FS:0是teb的位置,teb位移0x30的地方是peb
typedef struct _PEB {
 BOOLEAN InheritedAddressSpace;
 BOOLEAN ReadImageFileExecOptions;
 BOOLEAN BeingDebugged;
 BOOLEAN Spare;
 HANDLE Mutant;
 PVOID ImageBaseAddress;
 PPEB_LDR_DATA LoaderData;
 PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
 PVOID SubSystemData;
 PVOID ProcessHeap;
 PVOID FastPebLock;
 PPEBLOCKROUTINE FastPebLockRoutine;
 PPEBLOCKROUTINE FastPebUnlockRoutine;
 ULONG EnvironmentUpdateCount;
 PVOID *KernelCallbackTable;
 PVOID EventLogSection;
 PVOID EventLog;
 PPEB_FREE_BLOCK FreeList;
 ULONG TlsExpansionCounter;
 PVOID TlsBitmap;
 ULONG TlsBitmapBits[0x2];
 PVOID ReadOnlySharedMemoryBase;
 PVOID ReadOnlySharedMemoryHeap;
 PVOID *ReadOnlyStaticServerData;
 PVOID AnsiCodePageData;
 PVOID OemCodePageData;
 PVOID UnicodeCaseTableData;
 ULONG NumberOfProcessors;
 ULONG NtGlobalFlag;
 BYTE Spare2[0x4];
 LARGE_INTEGER CriticalSectionTimeout;
 ULONG HeapSegmentReserve;
 ULONG HeapSegmentCommit;
 ULONG HeapDeCommitTotalFreeThreshold;
 ULONG HeapDeCommitFreeBlockThreshold;
 ULONG NumberOfHeaps;
 ULONG MaximumNumberOfHeaps;
 PVOID **ProcessHeaps;
 PVOID GdiSharedHandleTable;
 PVOID ProcessStarterHelper;
 PVOID GdiDCAttributeList;
 PVOID LoaderLock;
 ULONG OSMajorVersion;
 ULONG OSMinorVersion;
 ULONG OSBuildNumber;
 ULONG OSPlatformId;
 ULONG ImageSubSystem;
 ULONG ImageSubSystemMajorVersion;
 ULONG ImageSubSystemMinorVersion;
 ULONG GdiHandleBuffer[0x22];
 ULONG PostProcessInitRoutine;
 ULONG TlsExpansionBitmap;
 BYTE TlsExpansionBitmapBits[0x80];
 ULONG SessionId;
} PEB, *PPEB;

PEB位移0x0c的地方就是PPEB_LDR_DATA LoaderData;
typedef struct _PEB_LDR_DATA {
 ULONG Length;
 BOOLEAN Initialized;
 PVOID SsHandle;
 LIST_ENTRY InLoadOrderModuleList;
 LIST_ENTRY InMemoryOrderModuleList;
 LIST_ENTRY InInitializationOrderModuleList;
} PEB_LDR_DATA, *PPEB_LDR_DATA;
其中有三個鏈表,每個元素都是結構
typedef struct _LDR_MODULE {
 LIST_ENTRY InLoadOrderModuleList;
 LIST_ENTRY InMemoryOrderModuleList;
 LIST_ENTRY InInitializationOrderModuleList;
 PVOID BaseAddress;
 PVOID EntryPoint;
 ULONG SizeOfImage;
 UNICODE_STRING FullDllName;
 UNICODE_STRING BaseDllName;
 ULONG Flags;
 SHORT LoadCount;
 SHORT TlsIndex;
 LIST_ENTRY HashTableEntry;
 ULONG TimeDateStamp;
} LDR_MODULE, *PLDR_MODULE;
通過LIST_ENTRY把每個進程用到的MODULE串起來,每個MODULE就是可執行檔或dll在記憶體中的映像,通過這

個連可以把進程用到的dll全都走一遍,而shellcode需要的是kernel32.dll的,它總是位於鏈表InInitializa

tionOrderModuleList的第一個元素
 mov    eax, fs:0x30                  // PEB
        mov    eax, [eax + 0x0c]            // PROCESS_MODULE_INFO
        mov    esi, [eax + 0x1c]            // InInitOrder.flink
        lodsd       

//得到kernel.dll所在的LDR_MODULE結構的InInitializationOrderModuleList地址
        mov    eax,[eax+8]      //一個LIST_ENTRY8個位元組
現在的eAx中就是kernel.dll在記憶體映像的開始位置,也就是它的hAndle值

找到了kernel.dll,下面的部分就和PE檔案的格式有關了,

 mov    ebx,eax                    // 取kernel32.dll的起始地址
        mov    esi,dword ptr [ebx+0x3C]  //u 在e_lfanew中得到pe heAder
        mov    esi,dword ptr [esi+ebx+0x78] //u export directory rvA
        add     esi,ebx     
        mov    edi,dword ptr [esi+0x20]   //u struct _IMAGE_EXPORT_DIRECTORY    

    //中AddressOfNames; // RVA from base of image
        add    edi,ebx
        mov    ecx,dword ptr [esi+0x14] //u AddressOfFunctions; // RVA from base of image
        xor    ebp,ebp
        push    esi
search_GetProcAddress:
        push    edi
        push    ecx
        mov    edi,dword ptr [edi]
        add    edi,ebx                    // 把輸出函數名表起始地址存人edi
        mov    esi,edx                    // 指令表起始地址存入esi
        //mov    ecx,0Eh                    // 函數getprocAddress長度為0Eh
        push    0xE
        pop    ecx
        repe    cmps byte ptr [esi],byte ptr [edi]
        je    search_GetProcAddress_ok
       
        pop    ecx
        pop    edi
        add    edi,4
        inc    ebp
        loop    search_GetProcAddress

search_GetProcAddress_ok:
        pop    ecx  
        pop    edi
        pop    esi
        mov    ecx,ebp
        mov    eax,dword ptr [esi+24h] //u AddressOfNameOrdinals; // RVA from base of image
        add    eax,ebx
        shl    ecx,1
        add    eax,ecx
        xor    ecx,ecx
        mov    cx,word ptr [eax]
        mov    eax,dword ptr [esi+1Ch] //AddressOfFunctions; // RVA from base of image
        add    eax,ebx
        shl    ecx,2
        add    eax,ecx
        mov    eax,dword ptr [eax]
        add    eax,ebx

在pe檔案中,最開始是IMAGE_DOS_HEADER結構
typedef struct _IMAGE_DOS_HEADER {      // DOS .EXE header
    WORD   e_magic;                     // Magic number
    WORD   e_cblp;                      // Bytes on last page of file
    WORD   e_cp;                        // Pages in file
    WORD   e_crlc;                      // Relocations
    WORD   e_cparhdr;                   // Size of header in paragraphs
    WORD   e_minalloc;                  // Minimum extra paragraphs needed
    WORD   e_maxalloc;                  // Maximum extra paragraphs needed
    WORD   e_ss;                        // Initial (relative) SS value
    WORD   e_sp;                        // Initial SP value
    WORD   e_csum;                      // Checksum
    WORD   e_ip;                        // Initial IP value
    WORD   e_cs;                        // Initial (relative) CS value
    WORD   e_lfarlc;                    // File address of relocation table
    WORD   e_ovno;                      // Overlay number
    WORD   e_res[4];                    // Reserved words
    WORD   e_oemid;                     // OEM identifier (for e_oeminfo)
    WORD   e_oeminfo;                   // OEM information; e_oemid specific
    WORD   e_res2[10];                  // Reserved words
    LONG   e_lfanew;                    // File address of new exe header
  } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;

mov    esi,dword ptr [ebx+0x3C]這一句就是得到LONG   e_lfanew,esi指向pe頭,由於是相對與檔案開始

的位移,所以esi+ebx才是kernell.dll的pe頭在記憶體中的位置,再加0x78,就指向DAtADirectory,
typedef struct _IMAGE_NT_HEADERS {
    DWORD Signature;
    IMAGE_FILE_HEADER FileHeader;
    IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
typedef struct _IMAGE_OPTIONAL_HEADER {
    //
    // Standard fields.
    //

    WORD    Magic;
    BYTE    MajorLinkerVersion;
    BYTE    MinorLinkerVersion;
    DWORD   SizeOfCode;
    DWORD   SizeOfInitializedData;
    DWORD   SizeOfUninitializedData;
    DWORD   AddressOfEntryPoint;
    DWORD   BaseOfCode;
    DWORD   BaseOfData;

    //
    // NT additional fields.
    //

    DWORD   ImageBase;
    DWORD   SectionAlignment;
    DWORD   FileAlignment;
    WORD    MajorOperatingSystemVersion;
    WORD    MinorOperatingSystemVersion;
    WORD    MajorImageVersion;
    WORD    MinorImageVersion;
    WORD    MajorSubsystemVersion;
    WORD    MinorSubsystemVersion;
    DWORD   Win32VersionValue;
    DWORD   SizeOfImage;
    DWORD   SizeOfHeaders;
    DWORD   CheckSum;
    WORD    Subsystem;
    WORD    DllCharacteristics;
    DWORD   SizeOfStackReserve;
    DWORD   SizeOfStackCommit;
    DWORD   SizeOfHeapReserve;
    DWORD   SizeOfHeapCommit;
    DWORD   LoaderFlags;
    DWORD   NumberOfRvaAndSizes;
    IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;

DAtADirectory第一個就是ExportDirectory,,加ebx就是在記憶體中的位置,每個Directory的開頭都是結構
typedef struct _IMAGE_EXPORT_DIRECTORY {
    DWORD   Characteristics;
    DWORD   TimeDateStamp;
    WORD    MajorVersion;
    WORD    MinorVersion;
    DWORD   Name;
    DWORD   Base;
    DWORD   NumberOfFunctions;
    DWORD   NumberOfNames;
    DWORD   AddressOfFunctions;     // RVA from base of image
    DWORD   AddressOfNames;         // RVA from base of image
    DWORD   AddressOfNameOrdinals;  // RVA from base of image
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;

AddressOfNAmes和它後面的地址是一個指標數組,每個元素都指向一個函數名字串的rvA,用的時候可以這


(char*)((*(int*)Addr)+bAseAddress)
AddressOfNAmeOrdinAls與AddressOfNAmes一一對應,是函數在AddressOfFunctions裡的序號

在調用這裡面的函數時,如果是用函數名在找的話,先在AddressOfNAmes找到對應的項,得到在這個指標
數組中的位置,用這個位置在AddressOfNAmeOrdinAls中索引出響應的元素,
  mov    ecx,ebp
        mov    eax,dword ptr [esi+24h] //u AddressOfNameOrdinals;
        add    eax,ebx
        shl    ecx,1
        add    eax,ecx
也就是這幾句的意思,AddressOfNAmeOrdinAls數組中每個元素大小都是WORD,所以shl ecx,1
 xor    ecx,ecx
        mov    cx,word ptr [eax]
得到cx用來在AddressOfFunctions;中索引,AddressOfFunctions中每一個元素的內容就是函數的rvA了,加上

kernell.dll的基址就得到在記憶體中地址了
 add    eax,ebx
        shl    ecx,1
        add    eax,ecx
        xor    ecx,ecx
        mov    cx,word ptr [eax]
        mov    eax,dword ptr [esi+1Ch] //AddressOfFunctions; // RVA from base of image
        add    eax,ebx
        shl    ecx,2
        add    eax,ecx
        mov    eax,dword ptr [eax]
        add    eax,ebx

得到GetProcAddress的地址後,用它可以得到LoAdLibrAry的地址,因為LoAdLibrAry也是kernel.dll裡匯出的

函數,,然後有了這兩個函數,,其他啥函數都不發愁了

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.