首页
社区
课程
招聘
[原创]古墓派反混淆与壳对抗:基于硬件断点的无痕HWBP-Trace算法demo开源
发表于: 2025-8-14 02:16 5256

[原创]古墓派反混淆与壳对抗:基于硬件断点的无痕HWBP-Trace算法demo开源

2025-8-14 02:16
5256

之前在帖子《古墓派反native混淆方案:实机调试》里提到的一套用于trace代码调用流程的一套算法,基于ptrace接口。

曾在各种BR跳转混淆库,以及臭名昭著某n_o_r_msg上跑出完整调用流程,在此开源下部分demo代码。

以下c代码组合一把梭哈编译成可执行文件便可实现一个HWBP-trace-server

核心trace逻辑代码:后面看情况补充注释更新一下

以下为包含主次进程生命流程代码,较为简单

最后写文件生成的trace文件示例,用以结合ida静态分析原始so库与内存dump文件

// ---------- ↓↓↓↓ 需要自己去实现的逻辑,暂不开源 ↓↓↓↓------------------
//内核接口:标志当前线程为server线程
void xxxx_setselfengine(void);
 
//内核接口:获取当前标记uid的、调用完ptrace_me陷入睡眠的线程
void xxxx_fetchOne(struct trace_info* &info);
 
//内核接口:声明当前线程为 线程[pid] 的专属tracer线程
void xxxx_markSelfTracer(int pid);
 
// 解析当前进程pc 地址后 2048长度内的指令(512条指令),获取下一条 跳转类 指令
void do_find_next_jump(unsigned long* next_pc);
 
// ---------- ↑↑↑↑ 需要自己去实现的逻辑,暂不开源 ↑↑↑↑ ------------------
 
 
 
 
 
// 进程静态变量
 
#define enable_trace true
 
//  是否是 bl blr类link跳转
static bool wrap_call=false;
 
//  是否是ret类型的跳转
static bool ret_call=false;
 
 
// 上一个安装的断点地址
static unsigned long last_hw_bp=0;
 
 
// 上一个安装 ret的断点地址
static unsigned long last_hw_bp_ret=0;
 
// 调试线程号
static int traced_tid;
 
 
// trace最大深度
#define MAX_TRACE_DEPTH 2
 
 
// link调用深度
static int call_depth = -MAX_TRACE_DEPTH;
 
// 入口点处的初始调用深度记录值,不变
static int orig_depth = -MAX_TRACE_DEPTH;
// ---------- ↓↓↓↓ 需要自己去实现的逻辑,暂不开源 ↓↓↓↓------------------
//内核接口:标志当前线程为server线程
void xxxx_setselfengine(void);
 
//内核接口:获取当前标记uid的、调用完ptrace_me陷入睡眠的线程
void xxxx_fetchOne(struct trace_info* &info);
 
//内核接口:声明当前线程为 线程[pid] 的专属tracer线程
void xxxx_markSelfTracer(int pid);
 
// 解析当前进程pc 地址后 2048长度内的指令(512条指令),获取下一条 跳转类 指令
void do_find_next_jump(unsigned long* next_pc);
 
// ---------- ↑↑↑↑ 需要自己去实现的逻辑,暂不开源 ↑↑↑↑ ------------------
 
 
 
 
 
// 进程静态变量
 
#define enable_trace true
 
//  是否是 bl blr类link跳转
static bool wrap_call=false;
 
//  是否是ret类型的跳转
static bool ret_call=false;
 
 
// 上一个安装的断点地址
static unsigned long last_hw_bp=0;
 
 
// 上一个安装 ret的断点地址
static unsigned long last_hw_bp_ret=0;
 
// 调试线程号
static int traced_tid;
 
 
// trace最大深度
#define MAX_TRACE_DEPTH 2
 
 
// link调用深度
static int call_depth = -MAX_TRACE_DEPTH;
 
// 入口点处的初始调用深度记录值,不变
static int orig_depth = -MAX_TRACE_DEPTH;
// ---------- ↓↓↓↓ 待补充和整理注释,这会有点写不动了 ↓↓↓↓------------------
int call_flow_analyze_do(bool norange){
     
    unsigned long pc=0;
 
    //获取目标线程当前pc后第一个跳转类指令的地址
    unsigned long next_j_addr = do_find_next_jump(&pc);
 
 
    // why do we stop in last phase?
    //
 
    //reasons:
    if(pc==last_hw_bp){
 
 
        // reason 1: hit at setted jump bp
        if(PRINT_CMDLINE)printf("\t\t------hbp stop: 0x%lx\n",pc);
 
        ptrace_remove_single_hwbp_at(traced_tid,pc);
 
 
        //未设置返回暂停,返回了
        if(ret_call&&last_hw_bp_ret==0){
            printf("\t\t------no hbp ret: 0x%lx\n",pc);
            printf("dep-1\n");
            call_depth-=1;
 
        }
 
        if(wrap_call){
            call_depth+=1;
            printf("dep+1\n");
        }
 
        //单步执行
        goto singlestep;
 
 
    }else if(pc==last_hw_bp_ret&&last_hw_bp_ret!=0){
 
        // reason 2: hit at a ret bp
        printf("\t\t------hbp ret: 0x%lx\n",pc);
        ptrace_remove_single_hwbp_at2(traced_tid,pc);
        last_hw_bp_ret=0;
 
 
        printf("dep-1\n");
        call_depth-=1;
 
 
        if(pc==next_j_addr){
 
            if(wrap_call){
                printf("dep+1\n");
                call_depth+=1;
            }
 
 
            if(ret_call){
                //next
                printf("dep-1\n");
                call_depth-=1;
                 
            }
 
            goto singlestep;
        }
         
        goto docont_wbp;
 
 
    }else{
        // reason 3: single stepped
 
        if(PRINT_CMDLINE)printf("\t\t------not a hbp, maybe step\n");
 
 
        // now we check deep call after singlestep
        if(call_depth >=0 && last_hw_bp_ret>0){
            //too deep
            doLogPcDeep(pc - so_range_start );//just log offset
 
            if(!do_cont(traced_tid)){
                printf("ptrace_cont fail\n");
            }
                 
            printf("\t\t---wait from sea---\n\n");
            return 0;
        }
 
         
 
 
        // check
        // we are out of range and we can trace link back
 
        if(last_hw_bp_ret>0&&(pc>so_range_end||pc<so_range_start)){\
 
            doLogPcOut(pc);
 
            //just continue it
            if(!do_cont(traced_tid))
                if(PRINT_CMDLINE)printf("ptrace_cont fail\n");
            printf("\t\t---wait for comingback---\n\n");
            return 0;
        }else if((pc>so_range_end||pc<so_range_start) && last_hw_bp_ret==0){
 
            if(!do_cont(traced_tid))
                if(PRINT_CMDLINE)printf("ptrace_cont fail\n");
 
            printf("\t\t---trace must be ended---\n\n");
 
            return 1;
        }
 
 
        // we steped on a call
 
        if(pc==next_j_addr){
 
            if(wrap_call){
                printf("dep+1\n");
                call_depth+=1;
                 
            }
 
            if(ret_call&&last_hw_bp_ret==0){
                //next
                printf("dep-1\n");
                call_depth-=1;
                 
            }
 
            goto singlestep;
        }
 
 
        goto docont_wbp;
 
    }
 
 
 
    // next phase
    singlestep:
 
        if(call_depth<=orig_depth){
            //we are out of trace reange
 
            doLogPc(pc - so_range_start );
 
            printf("\t\t---out of functions---\n\n");
 
            return 1;
 
        }
 
 
        if(pc>so_range_start&&pc<so_range_end&&!norange)
            doLogPc(pc - so_range_start );
 
        if(norange)
            doLogPc(pc);
 
 
        if(PRINT_CMDLINE)printf("\t\tdocont------wrap:%d ret:%d \n",wrap_call?1:0,ret_call?1:0);
 
 
        if(wrap_call){
            // just set return bp
            if(ptrace_install_single_hwbp_at3(traced_tid,next_j_addr)){
                last_hw_bp_ret=next_j_addr+4;// update
                if(PRINT_CMDLINE)printf("\t\t------set hbp ret before: 0x%lx\n",last_hw_bp_ret);
 
            }else
                printf("hbp set fail!!!\n");
        }
 
 
        // at branch point
        printf("\t\t------single-step\n");
 
        // do single step
        if(!do_single_step(traced_tid))
            printf("ptrace_single fail\n");
 
        return 0;
 
    // do continue with bp
 
    docont_wbp:
 
    // logpc
        if(pc>so_range_start&&pc<so_range_end&&!norange)
            doLogPc(pc - so_range_start );
 
        if(norange)
            doLogPc(pc);
 
 
        if(PRINT_CMDLINE)printf("\t\tdocont------wrap:%d ret:%d \n",wrap_call?1:0,ret_call?1:0);
 
         
 
        if(wrap_call){
 
            if(ptrace_install_single_hwbp_at2(traced_tid,next_j_addr)){
                last_hw_bp=next_j_addr;
 
                last_hw_bp_ret=next_j_addr+4;// update
 
                if(PRINT_CMDLINE)printf("\t\t------set hbp ret before: 0x%lx\n",last_hw_bp_ret);
            }
            else
                printf("hbp set fail!!!\n");
 
             
        }else{
 
            if(PRINT_CMDLINE)printf("\t\t------set hbp before: 0x%lx\n",next_j_addr);
 
            if(ptrace_install_single_hwbp_at(traced_tid,next_j_addr))
                last_hw_bp=next_j_addr;// update
            else
                printf("hbp set fail!!!\n");
 
        }
 
        if(!do_cont(traced_tid))
            printf("ptrace_cont fail\n");
 
        printf("\t\t------cont\n");
 
        return 0;
 
}
 
// ---------- ↑↑↑↑ 待补充和整理注释,这会有点写不动了 ↑↑↑↑ ------------------
// ---------- ↓↓↓↓ 待补充和整理注释,这会有点写不动了 ↓↓↓↓------------------
int call_flow_analyze_do(bool norange){
     
    unsigned long pc=0;
 
    //获取目标线程当前pc后第一个跳转类指令的地址
    unsigned long next_j_addr = do_find_next_jump(&pc);
 
 
    // why do we stop in last phase?
    //
 
    //reasons:
    if(pc==last_hw_bp){
 
 
        // reason 1: hit at setted jump bp
        if(PRINT_CMDLINE)printf("\t\t------hbp stop: 0x%lx\n",pc);
 
        ptrace_remove_single_hwbp_at(traced_tid,pc);
 
 
        //未设置返回暂停,返回了
        if(ret_call&&last_hw_bp_ret==0){
            printf("\t\t------no hbp ret: 0x%lx\n",pc);
            printf("dep-1\n");
            call_depth-=1;
 
        }
 
        if(wrap_call){
            call_depth+=1;
            printf("dep+1\n");
        }
 
        //单步执行
        goto singlestep;
 
 
    }else if(pc==last_hw_bp_ret&&last_hw_bp_ret!=0){
 
        // reason 2: hit at a ret bp
        printf("\t\t------hbp ret: 0x%lx\n",pc);
        ptrace_remove_single_hwbp_at2(traced_tid,pc);
        last_hw_bp_ret=0;
 
 
        printf("dep-1\n");
        call_depth-=1;
 
 
        if(pc==next_j_addr){
 
            if(wrap_call){
                printf("dep+1\n");
                call_depth+=1;
            }
 
 
            if(ret_call){
                //next
                printf("dep-1\n");
                call_depth-=1;
                 
            }
 
            goto singlestep;
        }
         
        goto docont_wbp;
 
 
    }else{
        // reason 3: single stepped
 
        if(PRINT_CMDLINE)printf("\t\t------not a hbp, maybe step\n");
 
 
        // now we check deep call after singlestep
        if(call_depth >=0 && last_hw_bp_ret>0){
            //too deep
            doLogPcDeep(pc - so_range_start );//just log offset
 
            if(!do_cont(traced_tid)){
                printf("ptrace_cont fail\n");
            }
                 
            printf("\t\t---wait from sea---\n\n");
            return 0;
        }
 
         
 
 
        // check
        // we are out of range and we can trace link back
 
        if(last_hw_bp_ret>0&&(pc>so_range_end||pc<so_range_start)){\
 
            doLogPcOut(pc);
 
            //just continue it
            if(!do_cont(traced_tid))
                if(PRINT_CMDLINE)printf("ptrace_cont fail\n");
            printf("\t\t---wait for comingback---\n\n");
            return 0;
        }else if((pc>so_range_end||pc<so_range_start) && last_hw_bp_ret==0){
 
            if(!do_cont(traced_tid))
                if(PRINT_CMDLINE)printf("ptrace_cont fail\n");
 
            printf("\t\t---trace must be ended---\n\n");
 
            return 1;
        }
 
 
        // we steped on a call
 
        if(pc==next_j_addr){
 
            if(wrap_call){
                printf("dep+1\n");
                call_depth+=1;
                 
            }
 
            if(ret_call&&last_hw_bp_ret==0){
                //next
                printf("dep-1\n");
                call_depth-=1;
                 
            }
 
            goto singlestep;
        }
 
 
        goto docont_wbp;
 
    }
 
 
 
    // next phase
    singlestep:
 
        if(call_depth<=orig_depth){
            //we are out of trace reange

传播安全知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 116
支持
分享
最新回复 (49)
雪    币: 7
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
2
大佬,yyds
2025-8-14 09:55
0
雪    币: 204
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
3
大佬,yyds
2025-8-14 09:59
0
雪    币: 18
活跃值: (1367)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
学习学习
2025-8-14 10:10
0
雪    币: 58
活跃值: (2286)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
5
666
2025-8-14 10:10
0
雪    币: 602
活跃值: (10228)
能力值: ( LV9,RANK:240 )
在线值:
发帖
回帖
粉丝
6
学习学习
2025-8-14 10:19
0
雪    币: 510
活跃值: (2072)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
学习
2025-8-14 10:20
0
雪    币: 343
活跃值: (1761)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
66
2025-8-14 10:22
0
雪    币: 2370
活跃值: (2936)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
666
2025-8-14 10:34
0
雪    币: 200
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
10
666
2025-8-14 10:46
0
雪    币: 4
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
11
666
2025-8-14 10:49
0
雪    币: 0
活跃值: (1560)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
6666,学习一下。
2025-8-14 11:01
0
雪    币: 104
活跃值: (7189)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
tql
2025-8-14 11:02
0
雪    币: 193
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
14
666
2025-8-14 12:54
0
雪    币: 0
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
15
666
2025-8-14 13:36
0
雪    币: 42
活跃值: (2811)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
666
2025-8-14 13:39
0
雪    币: 88
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
17
你的帖子非常有用,感谢分享!
2025-8-14 13:40
0
雪    币: 238
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
18
666
2025-8-14 13:56
0
雪    币: 1568
活跃值: (2026)
能力值: ( LV12,RANK:229 )
在线值:
发帖
回帖
粉丝
19
当年,全真教创始祖师王重阳举义反抗金兵,建造了一座大型仓库存放军粮物资,为了掩人耳目而设计成古墓形状。古墓其中机关众多。抗金义军失败后,王重阳愤而隐居古墓,自称将其称作“活死人墓”,意思是虽生犹死,与金人不共戴天。当世女侠林朝英对他一往情深,叹惜他一副大好身手埋没在一座坟墓之中,便使激将法将他骗出石墓,盼与王重阳携手同闯江湖。但王重阳于邦国之仇难以忘怀,时刻记着收复山河的家国大事,对林朝英的深情厚意虽然深知,但是只好装痴乔呆。林朝英还以为王重阳瞧她不起,终于在终南山与他比武决胜,以巧计赢得石墓赌注。从此她住在墓中,终身未曾复出,开创了古墓派。
2025-8-14 14:24
0
雪    币: 216
活跃值: (2700)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
666
2025-8-14 14:26
0
雪    币: 260
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
21
1
2025-8-14 16:17
0
雪    币: 20
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
22
666
2025-8-14 16:55
0
雪    币: 7
活跃值: (567)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
23
慕名学习
2025-8-14 19:05
0
雪    币: 0
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
24
666
2025-8-15 15:14
0
雪    币: 29
活跃值: (1729)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
25
66666666666
2025-8-17 08:54
0
游客
登录 | 注册 方可回帖
返回