跳至主要内容

反Hook 之自己实现GetProcAddress和LoadLibraryA(c++ version)

http://ift.tt/2AocAD0
// 课上练习.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <windows.h>
//要实现的功能:
/*
    自己实现GerProcAddress
    LoadLibraryA
*/


//思路:
/*
    GerProcAddress和LoadLibraryA都是在Kernel32.dll中的
    首要的任务就是找到Kernel32.dll,然后遍历IAT就能找到这两个函数
    现在首要的难点就是如何找到kernel32.dll()
    通过dll的加载顺序可以找到,而且虽然需要使用未文档化的API,但是好在windgb可以直接看,而且用到的也并不是很多
    懒得去晚上搜了,直接自己实现一个得了,作为演示,能用就行(最好还是搜一个正规的结构体)
*/

/*
0: kd> dt _TEB /a
nt!_TEB
+0x000 NtTib            : _NT_TIB
+0x01c EnvironmentPointer : Ptr32 Void
+0x020 ClientId         : _CLIENT_ID
+0x028 ActiveRpcHandle  : Ptr32 Void
+0x02c ThreadLocalStoragePointer : Ptr32 Void
+0x030 ProcessEnvironmentBlock : Ptr32 _PEB

//首先实现部分TEB结构体,因为只需要用的PEB的部分,所以实现到这就ok了
*/


//构建 TEB
typedef struct _TEB
{
    //保证0x30是peb的结构体就ok了
    struct _tem
    {
        DWORD a1;
        DWORD a2;
        DWORD a3;
        DWORD a4;
        DWORD a5;
        DWORD a6;
        DWORD a7;
        DWORD a8;
        DWORD a9;
        DWORD a10;
        DWORD a11;
        DWORD a12;
    }tem;
    DWORD _Peb;

}TEB,*PTEB;


//构建 局部 _PEB
/*
    0: kd> dt _PEB /b
    nt!_PEB
    +0x000 InheritedAddressSpace : UChar
    +0x001 ReadImageFileExecOptions : UChar
    +0x002 BeingDebugged    : UChar
    +0x003 BitField         : UChar
    +0x003 ImageUsesLargePages : Pos 0, 1 Bit
    +0x003 IsProtectedProcess : Pos 1, 1 Bit
    +0x003 IsLegacyProcess  : Pos 2, 1 Bit
    +0x003 IsImageDynamicallyRelocated : Pos 3, 1 Bit
    +0x003 SkipPatchingUser32Forwarders : Pos 4, 1 Bit
    +0x003 SpareBits        : Pos 5, 3 Bits
    +0x004 Mutant           : Ptr32
    +0x008 ImageBaseAddress : Ptr32
    +0x00c Ldr              : Ptr32
*/

typedef struct _PEB_LDR_DATA
{
    int Length;
    int Initialized;
    DWORD SsHandle;
    PLIST_ENTRY InLoadOrderModuleList; //只用到这里,所以到这就暂时ok吧
}PEB_LDR_DATA,*PPEB_LDR_DATA;

typedef struct _PEB
{
    DWORD tem1;
    DWORD tem2;
    DWORD tem3;
    PPEB_LDR_DATA Ldr; //需要先实现一个此结构体
}PEB,*PPEB;

typedef struct _LDR_DATA_TABLE_ENTRY
{
    struct InLoadOrderLinks
    {
        PLIST_ENTRY Flink;

        PLIST_ENTRY Blink;
    }InLoadOrderLinks;
    struct InMemoryOrderLinks
    {
        PLIST_ENTRY Flink;

        PLIST_ENTRY Blink;
    }InMemoryOrderLinks;
    struct InInitializationOrderLinks
    {
        PLIST_ENTRY Flink;

        PLIST_ENTRY Blink;
    }InInitializationOrderLinks;

    DWORD DllBase;//加载基址

}LDR_DATA_TABLE_ENTRY,*PLDR_DATA_TABLE_ENTRY;

//遍历导出表,然后根据函数名称,获取制定的函数地址

PVOID MyGetFnAddress(HMODULE hMoudle, const char * pProcName)
{
    PIMAGE_DOS_HEADER pDosHdr = (PIMAGE_DOS_HEADER)hMoudle;
    PIMAGE_NT_HEADERS pNtHdr = (PIMAGE_NT_HEADERS)(pDosHdr->e_lfanew + (ULONG_PTR)pDosHdr);
    PIMAGE_OPTIONAL_HEADER pOpHdr = (PIMAGE_OPTIONAL_HEADER)&pNtHdr->OptionalHeader;
    //获取到op头之后,就是获取导出表
    PIMAGE_EXPORT_DIRECTORY  pExportDir = (PIMAGE_EXPORT_DIRECTORY)(pOpHdr->DataDirectory[0].VirtualAddress+(ULONG)pDosHdr);


    DWORD *pEnt = (DWORD *)(pExportDir->AddressOfNames + (ULONG_PTR)pDosHdr);
    //然后就开始便利了,首先遍历的是导入名称表
    for (DWORD i =0;i<pExportDir->NumberOfNames;i++)
    {
        char * pEntName = (char*)(pEnt[i] + (ULONG_PTR)pDosHdr);
        if (strcmp(pProcName, pEntName)==0)
        {
            //说明找到了输入的函数名
            //然后去找这个函数名的在导出函数地址表中的地址
            WORD* pEot = (WORD* )(pExportDir->AddressOfNameOrdinals+(ULONG_PTR)pDosHdr);
            DWORD index = pEot[i];
            DWORD * pEat = (DWORD*)(pExportDir->AddressOfFunctions + (ULONG_PTR)pDosHdr);
            DWORD pFnAddress = pEat[index];
            return (PVOID)pFnAddress;
        }
    }
    //没有找到
    return NULL;
}


int main()
{
    
    //获取teb
    PTEB pTeb = NtCurrentTeb();
    //获取peb
    PPEB pPeb= (PPEB)pTeb->_Peb;
    
    //然后是找到ldr
    PPEB_LDR_DATA pLdr = pPeb->Ldr;

    //首先是获取InLoadOrderModuleList 
    PLIST_ENTRY pListEntry = pLdr->InLoadOrderModuleList->Flink;
    
    PLDR_DATA_TABLE_ENTRY pKernel32 = (PLDR_DATA_TABLE_ENTRY)pListEntry->Flink;

    HMODULE hMoudle = (HMODULE)pKernel32->DllBase;
    
    //定义两个函数指针
    /* 
    原型
    WINAPI
GetProcAddress(
    _In_ HMODULE hModule,
    _In_ LPCSTR lpProcName
    );

    HMODULE
    WINAPI
    LoadLibraryA(
    _In_ LPCSTR lpLibFileName
    );
    */
    typedef LPVOID(WINAPI* MYGETPROCADDRESS)(HMODULE hMoudle, LPCSTR lpProcName);
    typedef HMODULE(WINAPI*MYLOADLIBRARYA)(LPCSTR lpLibFileName);
    
    MYGETPROCADDRESS MyGetProcAddress = (MYGETPROCADDRESS)MyGetFnAddress(hMoudle, "GetProcAddress");
    MYLOADLIBRARYA MyLoadLibraryA = (MYLOADLIBRARYA)MyGetFnAddress(hMoudle, "LoadLibraryA");

//这就找到了这个2个api的地址,如果对方进行了自定义hook,这个时候大可以自定去读取OpCode进行判断

// c++ 写的比较麻烦,稍后用汇编写一个,比较简洁易懂


    return 0;
}


The post 反Hook 之自己实现GetProcAddress和LoadLibraryA(c++ version) appeared first on cole.

http://ift.tt/eA8V8J reverse engineering, reverse December 04, 2017 at 07:33PM

评论

此博客中的热门博文

IDA动态调试ELF中遇到的问题(1)

https://ift.tt/2Gxnf2F 遇到 got SIGCHLD singal(child status has changed)...这种提示 singal fork了子进程 直接点yes,然后继续单步执行,出来提示 pass to application就行了 内存查看 用od习惯了之后,凡事都想右键看一下内存,但是IDA中好像没有那么如意, 目前只是在栈中右键发现有查看hex的选项 动态调试的时候的nop ida保存动态调试的时候修改的数据 方法一:在程序运行的时候保存 The post IDA动态调试ELF中遇到的问题(1) appeared first on cole . https://ift.tt/2q9Qf5g WHATEVER April 05, 2018 at 09:44AM

32位ARM汇编语言(四)数据处理指令

http://ift.tt/2Gwa4v5 基本指令介绍 数据传送指令 比较指令 cmp{条件}操作数1,操作数2 CMN{条件}操作数1,操作数2 TST{条件},操作数1,操作数2 TEQ{条件} 操作数1,操作数2 算数逻辑运算指令 ADD{条件}{S}目的寄存器,操作数1,操作数2 ADC{条件}{S}目的寄存器,操作数1,操作数2 RSB{条件}{S}目的寄存器,操作数1,操作数2 RSC{条件}{S}目的寄存器,操作数1,操作数2 AND{条件}{S}目的寄存器,操作数1,操作数2 EOR{条件}{S}目的寄存器,操作数1,操作数2 BIC{条件}{S}目的寄存器,操作数1,操作数2 基本指令介绍 数据传送指令 数据传送指令用于在寄存器和储存器中之间进行数据的双向传输 比如:MOV ,MVN 算数逻辑运算指令 完成常用的算术与逻辑运算,该类指令不但将运算结果保存在目的寄存器中,同时更新CPSR中相应条件表示位 比如:ADD,ADC,SUB,SBC,RSB,RSC,AND,ORR,EOR,BIC 比较指令 不保存运算结果,只更新CPSR中相应的条件标志位 比如:CMP,CMN,TST,TEQ 数据传送指令 指令 描述 MOV{条件}{S}目的寄存器,操作数 数据传送指令 MVN{条件}{S}目的寄存器,操作数 数据取反传送指令 {S}选项决定指令的操作是否影响CPSR中条件标志位的值 MVN与MOV不同之处是在传送之前按位被取反 __asm__ ("mov ri,r0“); //将寄存器R0的值传送到寄存器R1 __asm__(”mov r1,r0,lsl#3"); //将寄存器R0的值左移3位后传到R1 __asm__(“mov pc,lr"); //将寄存器lr的值传送到pc,常用于子程序返回 __asm__("mvn r0,#0”); // 将立即数0 取反传送到寄存器R0中,完成后R0=-1 比较指令 指令 描述 CMP{条件}操作数1,操作数2 比较指令 CMN{条件}操作数1,操作数2 比较反值指令 TST{条件...