开启辅助访问 切换到宽版

精易论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

用微信号发送消息登录论坛

新人指南 邀请好友注册 - 我关注人的新帖 教你赚取精币 - 每日签到


求职/招聘- 论坛接单- 开发者大厅

论坛版规 总版规 - 建议/投诉 - 应聘版主 - 精华帖总集 积分说明 - 禁言标准 - 有奖举报

查看: 257|回复: 6
收起左侧

[C/C++] 求一个大手子,答疑一下为什么HOOK后跳转原地址会崩溃

[复制链接]
结帖率:67% (4/6)
发表于 前天 19:34 | 显示全部楼层 |阅读模式   四川省泸州市
5精币
我需要hook一个地址,获取它的参数修改后回到原函数,- -因为这个程序是linux的,所以用的c++加Ai写的so绑定的, 下面附上源码文件, 和动态汇编的截图  求个大手子答疑


汇编内容
[C++] 纯文本查看 复制代码
debug001:00000000006E633A ; ---------------------------------------------------------------------------
debug001:00000000006E633A
debug001:00000000006E633A loc_6E633A:                             ; CODE XREF: _ZN13Obj_Character9OnDamagesEPKiiiiiii+F↓j
debug001:00000000006E633A push    rbp
debug001:00000000006E633B mov     rbp, rsp
debug001:00000000006E633E push    r15
debug001:00000000006E6340 push    r14
debug001:00000000006E6342 push    r13
debug001:00000000006E6344 push    r12
debug001:00000000006E6346 push    rbx
debug001:00000000006E6347 sub     rsp, 48h
debug001:00000000006E634B mov     rbx, rdi
debug001:00000000006E634E mov     r13d, ecx
debug001:00000000006E6351 mov     r12d, r8d
debug001:00000000006E6354 mov     r15d, r9d
debug001:00000000006E6357 mov     eax, [rsi]
debug001:00000000006E6359 mov     [rbp-50h], eax
debug001:00000000006E635C mov     eax, [rsi+4]
debug001:00000000006E635F mov     [rbp-4Ch], eax
debug001:00000000006E6362 mov     eax, [rsi+8]
debug001:00000000006E6365 mov     [rbp-48h], eax
debug001:00000000006E6368 mov     eax, [rsi+0Ch]
debug001:00000000006E636B mov     [rbp-44h], eax
debug001:00000000006E636E mov     eax, [rsi+10h]
debug001:00000000006E6371 mov     [rbp-40h], eax
debug001:00000000006E6374 mov     eax, [rsi+14h]
debug001:00000000006E6377 mov     [rbp-3Ch], eax
debug001:00000000006E637A mov     esi, edx
debug001:00000000006E637C call    sub_6DED9E  汇编部分
cpp 代码 [mw_shl_code=cpp,true]#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <stdbool.h>
#include <dlfcn.h>
#include <string.h>
#include <stdint.h>
#include "damge.h"


char* temp_func;
typedef unsigned char       BYTE;
typedef unsigned long       DWORD;
typedef unsigned   int uint32_t;
typedef signed short int16_t;
typedef signed short WORD;

typedef int(*STRCMP)(const char*, const char*);

typedef int64_t (*OrigFuncType)(
    uint32_t *a1, int *a2, unsigned int a3, unsigned int a4,
    unsigned int a5, unsigned int a6, double a7, unsigned int a8, int a9
);
OrigFuncType orig_func = nullptr;
char* trampoline = nullptr;

void BuildTrampoline(uintptr_t target_addr, size_t patch_len)
{
    trampoline = (char *)mmap(nullptr, patch_len + 16, PROT_READ | PROT_WRITE | PROT_EXEC,
                              MAP_ANON | MAP_PRIVATE, -1, 0);
    memcpy(trampoline, (void *)target_addr, patch_len);

    uintptr_t jmp_back_addr = target_addr + patch_len;
    unsigned char* p = (unsigned char*)(trampoline + patch_len);

    // FF 25 00 00 00 00 [8字节绝对地址]
    *p++ = 0xFF;
    *p++ = 0x25;
    *(uint32_t*)p = 0;  // 32位偏移
    p += 4;
    *(uint64_t*)p = jmp_back_addr;

    orig_func = (OrigFuncType)trampoline;
}

CHook::CHook(void)
{


回答提醒:如果本帖被关闭无法回复,您有更好的答案帮助楼主解决,请发表至 源码区 可获得加分喔。
友情提醒:本版被采纳的主题可在 申请荣誉值 页面申请荣誉值,获得 1点 荣誉值,荣誉值可兑换荣誉会员、终身vip用户组。
快捷通道:申请荣誉值无答案申请取消悬赏投诉有答案未采纳为最佳
结帖率:67% (4/6)

签到天数: 1 天

 楼主| 发表于 前天 19:35 | 显示全部楼层   四川省泸州市
[C++] 纯文本查看 复制代码
#pragma once
typedef unsigned char       BYTE;
typedef unsigned long       DWORD;

typedef unsigned   int uint32_t;
struct t_Context
{
        DWORD EDI;
        DWORD ESI;
        DWORD EBP;
        DWORD ESP;
        DWORD EBX;
        DWORD EDX;
        DWORD ECX;
        DWORD EAX;
};

class CHook
{
public:
        CHook(void);
        ~CHook(void);
        // 添加Hook
        bool AddHook(DWORD dwHookAddr, void *pfnHookProc, DWORD tfnHookProc, DWORD dwHookAddr2);
        // 移除Hook
        bool RemoveHook();
        // 寄存器结构体
        t_Context m_Context;
        // 返回地址,没有特殊需求不要动这里
        DWORD m_dwRetAddr;
        DWORD m_JMPetAddr;
        DWORD m_dwRetArr ;

private:
        // 保存Hook地址,用于RemoveHook
        DWORD m_dwHookAddr;
        // 保存原始字节,用于RemoveHook
        BYTE m_OldCode[5];
};

void change_bytes(int addr, const char code[], int len);
bool change_addr_writable(long address, bool writable);

回复

使用道具 举报

结帖率:67% (4/6)

签到天数: 1 天

 楼主| 发表于 前天 19:36 | 显示全部楼层   四川省泸州市
[C++] 纯文本查看 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <stdbool.h>
#include <dlfcn.h>
#include <string.h>
#include <stdint.h> 
#include "damge.h"


char* temp_func;
typedef unsigned char       BYTE;
typedef unsigned long       DWORD;
typedef unsigned   int uint32_t;
typedef signed short int16_t;
typedef signed short WORD;

typedef int(*STRCMP)(const char*, const char*);

typedef int64_t (*OrigFuncType)(
    uint32_t *a1, int *a2, unsigned int a3, unsigned int a4,
    unsigned int a5, unsigned int a6, double a7, unsigned int a8, int a9
);
OrigFuncType orig_func = nullptr;
char* trampoline = nullptr;

void BuildTrampoline(uintptr_t target_addr, size_t patch_len)
{
    trampoline = (char *)mmap(nullptr, patch_len + 16, PROT_READ | PROT_WRITE | PROT_EXEC,
                              MAP_ANON | MAP_PRIVATE, -1, 0);
    memcpy(trampoline, (void *)target_addr, patch_len);

    uintptr_t jmp_back_addr = target_addr + patch_len;
    unsigned char* p = (unsigned char*)(trampoline + patch_len);

    // FF 25 00 00 00 00 [8字节绝对地址]
    *p++ = 0xFF;
    *p++ = 0x25;
    *(uint32_t*)p = 0;  // 32位偏移
    p += 4;
    *(uint64_t*)p = jmp_back_addr;

    orig_func = (OrigFuncType)trampoline;
}

CHook::CHook(void)
{
        memset(&m_Context, 0, sizeof(m_Context));
        memset(m_OldCode, 0x90, 5);
        m_dwRetAddr = 0;
        m_dwHookAddr = 0;
}


CHook::~CHook(void)
{
}

bool change_addr_writable(long address, bool writable) {
        long page_size = sysconf(_SC_PAGESIZE);
        long page_start = (address)& (~(page_size - 1));
        //printf("faild to init stubpage_start:%x\n", page_start);
        //change memory attribute
        if (writable == true) {
                return mprotect((void*)page_start, page_size, PROT_READ | PROT_WRITE | PROT_EXEC) != -1;
        }
        else {
                return mprotect((void*)page_start, page_size, PROT_READ | PROT_EXEC) != -1;
        }
}

//替换目标函数的前len个字节,使之跳转到hook函数
void change_bytes(uintptr_t addr, const char code[], int len)
{
        memcpy((void*)addr, code, len);
}

bool CHook::AddHookJMP(uintptr_t address, void *pfnHookProc)
{
    if (change_addr_writable(address, true))
    {
        // 使用更可靠的跳转指令
        BYTE jumpCode[14] = {0xFF, 0x25, 0x00, 0x00, 0x00, 0x00}; // jmp [rip+offset]
        uint64_t addr64 = (uint64_t)pfnHookProc;
        memcpy(&jumpCode[6], &addr64, 8);
        
        change_bytes(address, (const char*)jumpCode, 14);
        change_addr_writable(address, false);
        return true;
    }
    return false;
}


CHook hook1;


// 菁梦 尝试写个伤害回调看看 2025年6月6日14:20:16 - -第一次
int64_t my_hook_func(uint32_t *a1, int *a2, unsigned int a3, unsigned int a4,
                    unsigned int a5, unsigned int a6, double a7, unsigned int a8, int a9)
{
    printf(
        "\033[1;31m[伤害回调数据] 参数:\n"
        "  a1 = %p\n"
        "  a2 = %p\n"
        "  a3 = %u\n"
        "  a4 = %u\n"
        "  a5 = %u\n"
        "  a6 = %u\n"
        "  a7 = %f\n"
        "  a8 = %u\n"
        "  a9 = %d\n\033[0m",
        a1, a2, a3, a4, a5, a6, a7, a8, a9
    );

    int64_t ret = 0;
    if (orig_func) {
       printf("Before call orig_func: RIP=%p, RSP=%p\n", __builtin_return_address(0), __builtin_frame_address(0));
ret = orig_func(a1, a2, a3, a4, a5, a6, a7, a8, a9);
printf("After call orig_func: ret=%ld\n", ret);
    }
    return ret;
}





const char* asdas = "St5ctypeIcE";
int asas = 0;
int strcmp(const char *s1, const char *s2)
{
        unsigned long myfunctionaddr = 0x48;
        static void *handle = NULL;
        static STRCMP old_strcmp = NULL;
        if (!handle)
        {
                handle = dlopen("libc.so.6", RTLD_LAZY);
                old_strcmp = (STRCMP)dlsym(handle, "strcmp");
        }
        if (old_strcmp(s1, asdas) == 0){
                if (asas == 0){

                         // 计算patch长度,x64建议用14字节(避免截断指令)
            size_t patch_len = 2;        
            BuildTrampoline(0x6E633A, patch_len);

            // 对伤害函数跳转
            hook1.AddHookJMP(0x6E633A, (void *)my_hook_func);

                        asas = 1;
                }
        }
        return old_strcmp(s1, s2);
}

__attribute__((constructor))
void load()
{
        temp_func = (char*)mmap((void  *)0X3B0000, 4096, PROT_WRITE | PROT_EXEC | PROT_READ, MAP_ANON | MAP_PRIVATE, -1, 0);
}

#define RED     "\033[31m"
#define GREEN   "\033[32m"
#define YELLOW  "\033[33m"
#define BLUE    "\033[34m"
#define MAGENTA "\033[35m"
#define CYAN    "\033[36m"
#define WHITE   "\033[37m"
#define RESET   "\033[0m"




回复

使用道具 举报

结帖率:83% (10/12)

签到天数: 7 天

发表于 前天 21:49 | 显示全部楼层   重庆市重庆市
        // 需要在新的函数中调用原函数的新地址
        bool HookFunc(DWORD64 原始地址, DWORD64 新的地址, DWORD64* 原函数新地址)
        {
                char data = *(char*)原始地址;        // 强制访问一次
                Capstone cap; // 用于自动获取函数头部长度,最低需要14字节
                MemoryReadWrite mem;

                size_t len = cap.GetCodeLen((const uint8_t*)原始地址, 0x20, 14);
                if (len == 0)
                {
                        printf_s("Get Code Len Error \n");
                        return false;
                }

                // 检查地址是否被Hook
                if (*(DWORD32*)原始地址 == 0x25FF)
                {
                        printf_s("Already Hook ... \n");
                        return false;
                }

                // 构建新的原函数
                *原函数新地址 = (DWORD64)VirtualAlloc(NULL, 0x1000, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
                if (*原函数新地址 == NULL)
                {
                        printf_s("VirtualAlloc1 Error \n");
                        return false;
                }
                mem.GetAny(原始地址, (CHAR*)*原函数新地址, len);
                unsigned char code[] = { 0xFF, 0x25, 0x00 , 0x00 , 0x00 , 0x00 };
                mem.SetAny((*原函数新地址) + len, (CHAR*)code, sizeof(code));
                mem.Set64((*原函数新地址) + len + sizeof(code), 原始地址 + len);


                // 构建原函数起跳
                DWORD protect;
                mem.GetProtect(原始地址, &protect);
                mem.SetProtect(原始地址, PAGE_EXECUTE_READWRITE);
                mem.SetAny(原始地址, (CHAR*)code, sizeof(code));
                mem.Set64(原始地址 + sizeof(code), 新的地址);
                mem.SetProtect(原始地址, protect);
                return true;
        }
回复

使用道具 举报

结帖率:83% (10/12)

签到天数: 7 天

发表于 前天 21:51 | 显示全部楼层   重庆市重庆市
        // 需要在新的函数中调用原函数的新地址
        bool HookFunc(DWORD64 原始地址, DWORD64 新的地址, DWORD64* 原函数新地址)
        {
                char data = *(char*)原始地址;        // 强制访问一次
                Capstone cap; // 用于自动获取函数头部长度,最低需要14字节
                MemoryReadWrite mem;

                size_t len = cap.GetCodeLen((const uint8_t*)原始地址, 0x20, 14);
                if (len == 0)
                {
                        printf_s("Get Code Len Error \n");
                        return false;
                }

                // 检查地址是否被Hook
                if (*(DWORD32*)原始地址 == 0x25FF)
                {
                        printf_s("Already Hook ... \n");
                        return false;
                }

                // 构建新的原函数
                *原函数新地址 = (DWORD64)VirtualAlloc(NULL, 0x1000, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
                if (*原函数新地址 == NULL)
                {
                        printf_s("VirtualAlloc1 Error \n");
                        return false;
                }
                mem.GetAny(原始地址, (CHAR*)*原函数新地址, len);
                unsigned char code[] = { 0xFF, 0x25, 0x00 , 0x00 , 0x00 , 0x00 };
                mem.SetAny((*原函数新地址) + len, (CHAR*)code, sizeof(code));
                mem.Set64((*原函数新地址) + len + sizeof(code), 原始地址 + len);


                // 构建原函数起跳
                DWORD protect;
                mem.GetProtect(原始地址, &protect);
                mem.SetProtect(原始地址, PAGE_EXECUTE_READWRITE);
                mem.SetAny(原始地址, (CHAR*)code, sizeof(code));
                mem.Set64(原始地址 + sizeof(code), 新的地址);
                mem.SetProtect(原始地址, protect);
                return true;
        }


调用
                DWORD64 Addr;
                HookFunc((DWORD64)CreateThread, (DWORD64)MyCreateThread, &Addr);
                TrueCreateThread = (pCreateThread)Addr;
回调
HANDLE WINAPI MyCreateThread(
        LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter,
        DWORD dwCreationFlags, LPDWORD lpThreadId
) {
        return TrueCreateThread(lpThreadAttributes, dwStackSize, lpStartAddress, lpParameter, dwCreationFlags, lpThreadId);
}
回复

使用道具 举报

签到天数: 2 天

发表于 昨天 00:30 | 显示全部楼层   吉林省通化市
回复

使用道具 举报

签到天数: 2 天

发表于 昨天 00:41 | 显示全部楼层   吉林省通化市
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则 致发广告者

发布主题 收藏帖子 返回列表

sitemap| 易语言源码| 易语言教程| 易语言论坛| 易语言模块| 手机版| 广告投放| 精易论坛
拒绝任何人以任何形式在本论坛发表与中华人民共和国法律相抵触的言论,本站内容均为会员发表,并不代表精易立场!
论坛帖子内容仅用于技术交流学习和研究的目的,严禁用于非法目的,否则造成一切后果自负!如帖子内容侵害到你的权益,请联系我们!
防范网络诈骗,远离网络犯罪 违法和不良信息举报电话0663-3422125,QQ: 793400750,邮箱:wp@125.la
网站简介:精易论坛成立于2009年,是一个程序设计学习交流技术论坛,隶属于揭阳市揭东区精易科技有限公司所有。
Powered by Discuz! X3.4 揭阳市揭东区精易科技有限公司 ( 粤ICP备12094385号-1) 粤公网安备 44522102000125 增值电信业务经营许可证 粤B2-20192173

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