吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2020|回复: 1
收起左侧

[C&C++ 转载] inlinehook框架

[复制链接]
舒默哦 发表于 2020-5-12 12:34
本帖最后由 舒默哦 于 2020-5-12 12:52 编辑



步骤:
1.构造shellcode
2.寻找主程序的空白区域,插入shellcode
3.在被hook的地址跳转到这个空白区域,执行shellcode




运用:
把inlinehook.h添加到test_dll.dll这个工程里面


inlinehook的接口函数是SetHook() ,函数有四个参数,
参数一:进程句柄
参数二:要hook的地址
参数三:总共要hook多少个字节
参数四:hook之后要跳转的处理函数
注意:如果不用参数三,想要自动计算hook的字节数,需要用到反汇编引擎。


编译器用的vs2017,设置的是多字符集


编译完成后,用注入工具注入到"测试.exe"这个进程里面。
点击按钮就会触发这个inlinehook。

inlinehook.h
[C] 纯文本查看 复制代码
#include "CString.h"
#include <TlHelp32.h>

BYTE m_HookByte[20];//存放跳转的字节
BYTE m_OrigByte[20];//存放原始的字节
HANDLE m_hProcess;//存放进程句柄
DWORD m_nLength;//存放hook的长度
DWORD m_Addr;//存放要hook的地址
DWORD m_JmpFuncTion;//要跳转的函数

DWORD m_Jmp_Orig;//跳回到原来的地方继续执行

DWORD m_Blank_Area;//空白区域


//函数声明
void SetHook(HANDLE hProcess, DWORD Addr,DWORD nLength, DWORD CallBackFun);
void InjectShellCode();
void UnHook();

//寻找空白区域
DWORD Find_Blank();

/*
push xxxxxxxx
ret
*/
/*
参数一:进程句柄
参数二:要hook的地址
参数三:总共要hook多少个字节
参数四:hook之后要跳转的处理函数
*/
void SetHook(HANDLE hProcess, DWORD Addr, DWORD nLength, DWORD JmpFunTion)
{
    if (hProcess == NULL)
    {
        MessageBox(NULL, "句柄不能为空", "提示", MB_OK);
        return;
    }
    if (Addr == 0)
    {
        MessageBox(NULL, "要hook的地址不能为0", "提示", MB_OK);
        return;
    }

    if (nLength < 6)
    {
        MessageBox(NULL, "hook失败\r\n要hook的位置字节不足", "提示", MB_OK);
        return;
    }

    //初始化
    memset(m_HookByte, 0x90, sizeof(m_HookByte));
    memset(m_OrigByte, 0x90, sizeof(m_OrigByte));

    //1.1 保存句柄 地址 长度(卸载的时候要用到)
    m_hProcess = hProcess;
    m_Addr = Addr;
    m_nLength = nLength;
    m_JmpFuncTion = JmpFunTion;
    m_Jmp_Orig = Addr + nLength;

    if (Find_Blank()==0)
    {
        MessageBox(NULL, "寻找空白区域失败,注入不成功!", "提示", MB_OK);
        return;
    };

    m_HookByte[0] = 0x68;
    m_HookByte[5] = 0xc3;
    *(DWORD*)(m_HookByte + 1) = (DWORD)m_Blank_Area;

    //保存要hook的地方
    BOOL isRead = ReadProcessMemory(hProcess, (LPVOID)Addr, m_OrigByte, nLength, 0);
 
    if (isRead == 0)
    {
        MessageBox(NULL, "原始字节保存失败!", "提示", MB_OK);
    }

    DWORD written = 0;
    DWORD dwold;
    VirtualProtectEx(hProcess, (LPVOID)Addr, nLength, PAGE_EXECUTE_READWRITE, &dwold);

    WriteProcessMemory(hProcess, (LPVOID)Addr, m_HookByte, nLength, &written);

    VirtualProtectEx(hProcess, (LPVOID)Addr, nLength, dwold, &dwold);

    InjectShellCode();

   
}

//获取进程主模块的基址和大小
void GetModuleInf(DWORD* BaseAddr, DWORD* BaseSize)
{
    //1 获取进程主模块的基址和大小
    HANDLE        hModuleSnap = INVALID_HANDLE_VALUE;
    MODULEENTRY32 me32 = { sizeof(MODULEENTRY32) };
    //1. 创建一个模块相关的快照句柄
    hModuleSnap = CreateToolhelp32Snapshot(
        TH32CS_SNAPMODULE,  // 指定快照的类型
        GetCurrentProcessId());            // 指定进程
    if (hModuleSnap == INVALID_HANDLE_VALUE)
        return;
    //2. 通过模块快照句柄获取第一个模块信息
    if (!Module32First(hModuleSnap, &me32)) {
        CloseHandle(hModuleSnap);
        return;
    }
    //3. 循环获取模块信息
    do {
        /*printf("模块基址:%d,模块大小:%d,模块名称:%s\n",
            me32.modBaseAddr, me32.modBaseSize, me32.szModule);*/
        CString str = me32.szModule;
        if (strcmp(str.CutFromRight(3).MakeLower().GetString(), "exe") == 0)
        {
            *BaseAddr = (DWORD)me32.modBaseAddr;
            *BaseSize = me32.modBaseSize;
            break;
        }

    } while (Module32Next(hModuleSnap, &me32));
    //4. 关闭句柄并退出函数
    CloseHandle(hModuleSnap);
}



DWORD Find_Blank()
{
    DWORD BaseAddr = 0;//主模块的基址
    DWORD BaseSize = 0;//模块的大小
    //DWORD BaseCode = 0;//代码基址

    //获取主模块基址和大小
    GetModuleInf(&BaseAddr, &BaseSize);

    MEMORY_BASIC_INFORMATION Mem_Info;
    if (VirtualQueryEx(GetCurrentProcess(), (LPCVOID)(0x401000), &Mem_Info, 28) == 0)
    {
        MessageBox(NULL, "模块信息获取失败!", "", MB_ICONINFORMATION);
        return 0;
    }
    char* strbuff = new char[Mem_Info.RegionSize + 1];
    if (ReadProcessMemory(GetCurrentProcess(), (LPCVOID)(0x401000), strbuff, Mem_Info.RegionSize, 0) == 0)
    {
        MessageBox(NULL, "分析时读取内存失败!", "", MB_ICONINFORMATION);
        return 0;
    }

    char temp_k[] = { //易语言的0xcc较多,如果是c语言写的程序用0x00来找
        0xCC,0xCC, 0xCC,0xCC, 0xCC,0xCC, 0xCC,0xCC, 0xCC,0xCC, 
        0xCC,0xCC, 0xCC,0xCC, 0xCC,0xCC, 0xCC,0xCC, 0xCC,0xCC,
        0xCC,0xCC, 0xCC,0xCC, 0xCC,0xCC, 0xCC,0xCC, 0xCC,0xCC,
        0xCC,0xCC, 0xCC,0xCC, 0xCC,0xCC, 0xCC,0xCC, 0xCC,0xCC,
        0xCC,0xCC, 0xCC,0xCC, 0xCC,0xCC, 0xCC,0xCC, 0xCC,0xCC
    };

    CString strTotal = "找空白区域";
    //寻找二进制,我在CString类封装了一个方法Find_Memory_Bytes,代码贴在后面
    DWORD Blank = strTotal.Find_Memory_Bytes(strbuff, temp_k, BaseSize- sizeof(temp_k),sizeof(temp_k));

    if (Blank==0)
    {
        MessageBox(NULL, "空白区域寻找失败", "提示", MB_OK);
        return 0;
    }

    Blank = Blank - (DWORD)strbuff + 0x401000;
    m_Blank_Area = Blank;
    //CString ss = Blank;
    //MessageBox(NULL, ss.GetString(), "找到空白区域了", MB_OK);

    return Blank;
}


//插入ShellCode
void InjectShellCode()
{
    char ShellCode[] = {
        0x60,0x9C,0xB8,
        m_JmpFuncTion & 0xFF,(m_JmpFuncTion & 0xFF00) >> 8,(m_JmpFuncTion & 0xFF0000) >> 16,m_JmpFuncTion >> 24,
        0xFF,0xD0,
         0x9D,0x61,
        m_OrigByte[0],m_OrigByte[1],m_OrigByte[2],m_OrigByte[3],m_OrigByte[4],m_OrigByte[5],m_OrigByte[6],m_OrigByte[7],
        m_OrigByte[8],m_OrigByte[9],m_OrigByte[10],m_OrigByte[11],m_OrigByte[12],m_OrigByte[13],m_OrigByte[14],m_OrigByte[15],
        m_OrigByte[16],m_OrigByte[17],m_OrigByte[18],m_OrigByte[19],
        0x68,
        m_Jmp_Orig & 0xFF,(m_Jmp_Orig & 0xFF00) >> 8,(m_Jmp_Orig & 0xFF0000) >> 16,m_Jmp_Orig >> 24,
        0xC3
    };

    DWORD written = 0;
    DWORD dwold;
    VirtualProtectEx(m_hProcess,(LPVOID)m_Blank_Area, sizeof(ShellCode), PAGE_EXECUTE_READWRITE, &dwold);

    WriteProcessMemory(m_hProcess, (LPVOID)m_Blank_Area, ShellCode, sizeof(ShellCode), &written);
    

    VirtualProtectEx(m_hProcess,(LPVOID)m_Blank_Area, sizeof(ShellCode), dwold, &dwold);
}

//卸载hook
void UnHook()
{
    DWORD written = 0;
    DWORD dwold;
    VirtualProtectEx(m_hProcess, (LPVOID)m_Addr, m_nLength, PAGE_EXECUTE_READWRITE, &dwold);

    WriteProcessMemory(m_hProcess, (LPVOID)m_Addr, m_OrigByte, m_nLength, &written);

    VirtualProtectEx(m_hProcess, (LPVOID)m_Addr, m_nLength, dwold, &dwold);
}


test_dll.dll
[C] 纯文本查看 复制代码
#include "InlineHook.h"

void CallBack()
{
    //MessageBox(NULL, "测试成功", "提示", MB_OK);
    //定义创建进程需要用的结构体                                                                        
    STARTUPINFO si = { 0 };
    PROCESS_INFORMATION pi;
    si.cb = sizeof(si);

    //创建子进程                                                                        
    BOOL res = CreateProcess(
        (LPSTR)"网络流量监控.exe"
        ,NULL,
        NULL,
        NULL,
        TRUE,                                 //TRUE的时候,说明子进程可以继承父进程的句柄表                                
        CREATE_NEW_CONSOLE,
        NULL,
        NULL, &si, &pi);
 //这儿必定会失败,因为目录不对
    if (res==0)
    {
        MessageBox(NULL, "子进程创建失败!", "", MB_OK);
    }
    //UnHook();
}

//线程回调函数
DWORD WINAPI ThreadProc(LPVOID lpParameter)
{

    SetHook(GetCurrentProcess(), 0x00401154, 6, (DWORD)CallBack);
    return 0;
}

BOOL APIENTRY DllMain(HMODULE hModule,
    DWORD  ul_reason_for_call,
    LPVOID lpReserved
)
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    {
        MessageBox(NULL, "注入成功", "恭喜", MB_OK);
        //创建一个新线程
        HANDLE hTread = ::CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);
        ::CloseHandle(hTread);

    }

    case DLL_THREAD_ATTACH:
        //MessageBox(NULL, "DLL_THREAD_ATTACH", "", MB_OK);
    case DLL_THREAD_DETACH:
        //MessageBox(NULL, "DLL_THREAD_DETACH", "", MB_OK);
    case DLL_PROCESS_DETACH:
        //MessageBox(NULL, "DLL_PROCESS_DETACH", "", MB_OK);
        break;
    }
    return TRUE;
}


寻找二进制的方法
[C++] 纯文本查看 复制代码
/*
在指定内存查找目标二进制

@strRes[]:要查找的内存
@strTar[]:目标二进制
@nLenRes[]:要查找的内存的长度
@nLenTar[]:目标二进制的长度

成功返回:匹配到的内存地址
失败返回:0

目标二进制的书写格式: char strTar[]={0xE8,0x80,0x65,0x67,0x89};

注意:可以支持模糊匹配,通配符是'*',比如0xE8后面的地址是变化的,
        则目标二进制可以这样写char strTar[]={0xE8,'*','*','*','*',0x80,0x65}。

*/

DWORD CString::Find_Memory_Bytes(char * strRes, char * strTar, int nLenRes, int nLenTar)
{
    int calc = 0;

    for (int i = 0; i < nLenRes; ++i)
    {
        if (strRes[i] == strTar[calc] || strTar[calc] == '*')
        {
            ++calc;
        }
        else
        {
            calc = 0;
        }

        if (calc == nLenTar)
        {
            return  (DWORD)strRes + i - nLenTar + 1 ;
        }
    }
    return 0;
}



输出结果
1.png
2.png
3.png
4.png

测试.7z

496.21 KB, 下载次数: 19, 下载积分: 吾爱币 -1 CB

免费评分

参与人数 1吾爱币 +5 热心值 +1 收起 理由
苏紫方璇 + 5 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

hszt 发表于 2020-7-15 08:18
感谢分享,收藏备用
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-6-12 20:11

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表