@xiangzhai wrote:
Hi Hackers,
反向工程、防反向是永恒的博弈艺术
引子:我这两天学习如何编写一个LLVM PASS 纯练手写了一个LLVM “防”反向工程 PASS——ARE(Anti Reverse Engeering) 很KISS(Keep It Simple and Stupid),请大大们轻轻拍砖,目前70+行,实现了:
- 修改函数名称
.text .file "test-are.c" .globl login # -- Begin function login .p2align 4, 0x90 .type login,@function login: # @login .cfi_startproc # BB#0: pushq %rbp .Lcfi0: .cfi_def_cfa_offset 16 .Lcfi1: .cfi_offset %rbp, -16 movq %rsp, %rbp .Lcfi2: .cfi_def_cfa_register %rbp subq $32, %rsp movabsq $.L.str, %rax movabsq $.L.str.1, %rcx movq %rdi, -24(%rbp) movq %rsi, -16(%rbp) movq %rax, %rdi movq %rcx, %rsi movl $6, %edx movb $0, %al callq printf cmpq $0, -24(%rbp) je .LBB0_2 # BB#1: cmpq $0, -16(%rbp) jne .LBB0_3 .LBB0_2: movl $-1, -4(%rbp) jmp .LBB0_4 .LBB0_3: movl $0, -4(%rbp) .LBB0_4: movl -4(%rbp), %eax addq $32, %rsp popq %rbp retq .Lfunc_end0: .size login, .Lfunc_end0-login .cfi_endproc # -- End function .globl logout # -- Begin function logout .p2align 4, 0x90 .type logout,@function logout: # @logout .cfi_startproc # BB#0: pushq %rbp .Lcfi3: .cfi_def_cfa_offset 16 .Lcfi4: .cfi_offset %rbp, -16 movq %rsp, %rbp .Lcfi5: .cfi_def_cfa_register %rbp subq $16, %rsp movabsq $.L.str.2, %rax movabsq $.L.str.1, %rsi movl %edi, -4(%rbp) movl -4(%rbp), %ecx movq %rax, %rdi movl $14, %edx movb $0, %al callq printf xorl %eax, %eax addq $16, %rsp popq %rbp retq .Lfunc_end1: .size logout, .Lfunc_end1-logout .cfi_endproc # -- End function .globl main # -- Begin function main .p2align 4, 0x90 .type main,@function main: # @main .cfi_startproc # BB#0: pushq %rbp .Lcfi6: .cfi_def_cfa_offset 16 .Lcfi7: .cfi_offset %rbp, -16 movq %rsp, %rbp .Lcfi8: .cfi_def_cfa_register %rbp subq $32, %rsp movabsq $.L.str.4, %rax movabsq $.L.str.5, %rcx movabsq $.L.str.3, %rdx movl $0, -8(%rbp) movl %edi, -4(%rbp) movq %rsi, -24(%rbp) movq %rdx, -16(%rbp) movq %rax, %rdi movq %rcx, %rsi movb $0, %al callq printf xorl %edi, %edi xorl %esi, %esi callq login movl $4294967295, %edi # imm = 0xFFFFFFFF callq logout xorl %eax, %eax addq $32, %rsp popq %rbp retq .Lfunc_end2: .size main, .Lfunc_end2-main .cfi_endproc # -- End function .type .L.str,@object # @.str .section .rodata.str1.1,"aMS",@progbits,1 .L.str: .asciz "DEBUG: %s, line %d\n" .size .L.str, 20 .type .L.str.1,@object # @.str.1 .L.str.1: .asciz "test-are.c" .size .L.str.1, 11 .type .L.str.2,@object # @.str.2 .L.str.2: .asciz "DEBUG: %s, line %d: ID %d\n" .size .L.str.2, 27 .type .L.str.3,@object # @.str.3 .L.str.3: .asciz "Vml5Z0pFZGk9UHg2a2dPY0loZW49S3cxN3dVQUFBPT0" .size .L.str.3, 44 .type .L.str.4,@object # @.str.4 .L.str.4: .asciz "Hello world: %s\n" .size .L.str.4, 17 .type .L.str.5,@object # @.str.5 .L.str.5: .asciz "6xxzcQMhb4WgKX0EUkwG747K" .size .L.str.5, 25 .ident "Fedora clang version 6.0.0 (trunk 311323) (based on LLVM 6.0.0svn-r311323)" .section ".note.GNU-stack","",@progbits
将敏感的函数名,例如login、logout,修改成“无意义”的:
.text .file "test-are.c" .globl dragonball1 # -- Begin function dragonball1 .p2align 4, 0x90 .type dragonball1,@function dragonball1: # @dragonball1 .cfi_startproc # BB#0: pushq %rbp .Lcfi0: .cfi_def_cfa_offset 16 .Lcfi1: .cfi_offset %rbp, -16 movq %rsp, %rbp .Lcfi2: .cfi_def_cfa_register %rbp subq $32, %rsp movabsq $.L.str, %rax movabsq $.L.str.1, %rcx movq %rdi, -24(%rbp) movq %rsi, -16(%rbp) movq %rax, %rdi movq %rcx, %rsi movl $6, %edx movb $0, %al callq printf cmpq $0, -24(%rbp) je .LBB0_2 # BB#1: cmpq $0, -16(%rbp) jne .LBB0_3 .LBB0_2: movl $-1, -4(%rbp) jmp .LBB0_4 .LBB0_3: movl $0, -4(%rbp) .LBB0_4: movl -4(%rbp), %eax addq $32, %rsp popq %rbp retq .Lfunc_end0: .size dragonball1, .Lfunc_end0-dragonball1 .cfi_endproc # -- End function .globl dragonball2 # -- Begin function dragonball2 .p2align 4, 0x90 .type dragonball2,@function dragonball2: # @dragonball2 .cfi_startproc # BB#0: pushq %rbp .Lcfi3: .cfi_def_cfa_offset 16 .Lcfi4: .cfi_offset %rbp, -16 movq %rsp, %rbp .Lcfi5: .cfi_def_cfa_register %rbp subq $16, %rsp movabsq $.L.str.2, %rax movabsq $.L.str.1, %rsi movl %edi, -4(%rbp) movl -4(%rbp), %ecx movq %rax, %rdi movl $14, %edx movb $0, %al callq printf xorl %eax, %eax addq $16, %rsp popq %rbp retq .Lfunc_end1: .size dragonball2, .Lfunc_end1-dragonball2 .cfi_endproc # -- End function .globl main # -- Begin function main .p2align 4, 0x90 .type main,@function main: # @main .cfi_startproc # BB#0: pushq %rbp .Lcfi6: .cfi_def_cfa_offset 16 .Lcfi7: .cfi_offset %rbp, -16 movq %rsp, %rbp .Lcfi8: .cfi_def_cfa_register %rbp subq $32, %rsp movabsq $.L.str.4, %rax movabsq $.L.str.5, %rcx movabsq $.L.str.3, %rdx movl $0, -8(%rbp) movl %edi, -4(%rbp) movq %rsi, -24(%rbp) movq %rdx, -16(%rbp) movq %rax, %rdi movq %rcx, %rsi movb $0, %al callq printf xorl %edi, %edi xorl %esi, %esi callq dragonball1 movl $4294967295, %edi # imm = 0xFFFFFFFF callq dragonball2 xorl %eax, %eax addq $32, %rsp popq %rbp retq .Lfunc_end2: .size main, .Lfunc_end2-main .cfi_endproc # -- End function .type .L.str,@object # @.str .section .rodata.str1.1,"aMS",@progbits,1 .L.str: .asciz "DEBUG: %s, line %d\n" .size .L.str, 20 .type .L.str.1,@object # @.str.1 .L.str.1: .asciz "test-are.c" .size .L.str.1, 11 .type .L.str.2,@object # @.str.2 .L.str.2: .asciz "DEBUG: %s, line %d: ID %d\n" .size .L.str.2, 27 .type .L.str.3,@object # @.str.3 .L.str.3: .asciz "Vml5Z0pFZGk9UHg2a2dPY0loZW49S3cxN3dVQUFBPT0" .size .L.str.3, 44 .type .L.str.4,@object # @.str.4 .L.str.4: .asciz "Hello world: %s\n" .size .L.str.4, 17 .type .L.str.5,@object # @.str.5 .L.str.5: .asciz "6xxzcQMhb4WgKX0EUkwG747K" .size .L.str.5, 25 .ident "Fedora clang version 6.0.0 (trunk 311323) (based on LLVM 6.0.0svn-r311323)" .section ".note.GNU-stack","",@progbits
TODO 还未实现的功能:
- 使常量“人类”不可读,直接修改LLVM IR的Constant:
; ModuleID = 'test-are-mod.bc' source_filename = "test-are.c" target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-redhat-linux" @.str = private unnamed_addr constant [20 x i8] c"DEBUG: %s, line %d\0A\00", align 1 @.str.1 = private unnamed_addr constant [11 x i8] c"test-are.c\00", align 1 @.str.2 = private unnamed_addr constant [27 x i8] c"DEBUG: %s, line %d: ID %d\0A\00", align 1 @.str.3 = private unnamed_addr constant [44 x i8] c"Vml5Z0pFZGk9UHg2a2dPY0loZW49S3cxN3dVQUFBPT0\00", align 1 @.str.4 = private unnamed_addr constant [17 x i8] c"Hello world: %s\0A\00", align 1 @.str.5 = private unnamed_addr constant [25 x i8] c"6xxzcQMhb4WgKX0EUkwG747K\00", align 1 ; Function Attrs: noinline nounwind optnone uwtable define i32 @dragonball1(i8*, i8*) #0 { %3 = alloca i32, align 4 %4 = alloca i8*, align 8 %5 = alloca i8*, align 8 store i8* %0, i8** %4, align 8 store i8* %1, i8** %5, align 8 %6 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([20 x i8], [20 x i8]* @.str, i32 0, i32 0), i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.1, i32 0, i32 0), i32 6) %7 = load i8*, i8** %4, align 8 %8 = icmp ne i8* %7, null br i1 %8, label %9, label %12 ; <label>:9: ; preds = %2 %10 = load i8*, i8** %5, align 8 %11 = icmp ne i8* %10, null br i1 %11, label %13, label %12 ; <label>:12: ; preds = %9, %2 store i32 -1, i32* %3, align 4 br label %14 ; <label>:13: ; preds = %9 store i32 0, i32* %3, align 4 br label %14 ; <label>:14: ; preds = %13, %12 %15 = load i32, i32* %3, align 4 ret i32 %15 } declare i32 @printf(i8*, ...) #1 ; Function Attrs: noinline nounwind optnone uwtable define i32 @dragonball2(i32) #0 { %2 = alloca i32, align 4 store i32 %0, i32* %2, align 4 %3 = load i32, i32* %2, align 4 %4 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([27 x i8], [27 x i8]* @.str.2, i32 0, i32 0), i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.1, i32 0, i32 0), i32 14, i32 %3) ret i32 0 } ; Function Attrs: noinline nounwind optnone uwtable define i32 @main(i32, i8**) #0 { %3 = alloca i32, align 4 %4 = alloca i32, align 4 %5 = alloca i8**, align 8 %6 = alloca i8*, align 8 store i32 0, i32* %3, align 4 store i32 %0, i32* %4, align 4 store i8** %1, i8*** %5, align 8 store i8* getelementptr inbounds ([44 x i8], [44 x i8]* @.str.3, i32 0, i32 0), i8** %6, align 8 %7 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([17 x i8], [17 x i8]* @.str.4, i32 0, i32 0), i8* getelementptr inbounds ([25 x i8], [25 x i8]* @.str.5, i32 0, i32 0)) %8 = call i32 @dragonball1(i8* null, i8* null) %9 = call i32 @dragonball2(i32 -1) ret i32 0 } attributes #0 = { noinline nounwind optnone uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.module.flags = !{!0} !llvm.ident = !{!1} !0 = !{i32 1, !"wchar_size", i32 4} !1 = !{!"Fedora clang version 6.0.0 (trunk 311323) (based on LLVM 6.0.0svn-r311323)"}
将敏感的常量,例如SKEY,变成“人类”不可读的:
.text .file "test-are.c" .globl dragonball1 # -- Begin function dragonball1 .p2align 4, 0x90 .type dragonball1,@function dragonball1: # @dragonball1 .cfi_startproc # BB#0: pushq %rbp .Lcfi0: .cfi_def_cfa_offset 16 .Lcfi1: .cfi_offset %rbp, -16 movq %rsp, %rbp .Lcfi2: .cfi_def_cfa_register %rbp subq $32, %rsp movabsq $.L.str, %rax movabsq $.L.str.1, %rcx movq %rdi, -24(%rbp) movq %rsi, -16(%rbp) movq %rax, %rdi movq %rcx, %rsi movl $6, %edx movb $0, %al callq printf cmpq $0, -24(%rbp) je .LBB0_2 # BB#1: cmpq $0, -16(%rbp) jne .LBB0_3 .LBB0_2: movl $-1, -4(%rbp) jmp .LBB0_4 .LBB0_3: movl $0, -4(%rbp) .LBB0_4: movl -4(%rbp), %eax addq $32, %rsp popq %rbp retq .Lfunc_end0: .size dragonball1, .Lfunc_end0-dragonball1 .cfi_endproc # -- End function .globl dragonball2 # -- Begin function dragonball2 .p2align 4, 0x90 .type dragonball2,@function dragonball2: # @dragonball2 .cfi_startproc # BB#0: pushq %rbp .Lcfi3: .cfi_def_cfa_offset 16 .Lcfi4: .cfi_offset %rbp, -16 movq %rsp, %rbp .Lcfi5: .cfi_def_cfa_register %rbp subq $16, %rsp movabsq $.L.str.2, %rax movabsq $.L.str.1, %rsi movl %edi, -4(%rbp) movl -4(%rbp), %ecx movq %rax, %rdi movl $14, %edx movb $0, %al callq printf xorl %eax, %eax addq $16, %rsp popq %rbp retq .Lfunc_end1: .size dragonball2, .Lfunc_end1-dragonball2 .cfi_endproc # -- End function .globl main # -- Begin function main .p2align 4, 0x90 .type main,@function main: # @main .cfi_startproc # BB#0: pushq %rbp .Lcfi6: .cfi_def_cfa_offset 16 .Lcfi7: .cfi_offset %rbp, -16 movq %rsp, %rbp .Lcfi8: .cfi_def_cfa_register %rbp subq $32, %rsp movabsq $.L.str.4, %rax movabsq $.L.str.5, %rcx movabsq $.L.str.3, %rdx movl $0, -8(%rbp) movl %edi, -4(%rbp) movq %rsi, -24(%rbp) movq %rdx, -16(%rbp) movq %rax, %rdi movq %rcx, %rsi movb $0, %al callq printf xorl %edi, %edi xorl %esi, %esi callq dragonball1 movl $4294967295, %edi # imm = 0xFFFFFFFF callq dragonball2 xorl %eax, %eax addq $32, %rsp popq %rbp retq .Lfunc_end2: .size main, .Lfunc_end2-main .cfi_endproc # -- End function .type .L.str,@object # @.str .section .rodata.str1.1,"aMS",@progbits,1 .L.str: .asciz "DEBUG: %s, line %d\n" .size .L.str, 20 .type .L.str.1,@object # @.str.1 .L.str.1: .asciz "test-are.c" .size .L.str.1, 11 .type .L.str.2,@object # @.str.2 .L.str.2: .asciz "DEBUG: %s, line %d: ID %d\n" .size .L.str.2, 27 .type .L.str.3,@object # @.str.3 .L.str.3: .asciz "Vml5Z0pFZGk9UHg2a2dPY0loZW49S3cxN3dVQUFBPT0" .size .L.str.3, 44 .type main.buf,@object # @main.buf .section .rodata,"a",@progbits main.buf: .ascii "\0224Vx" # 人类不可读 .size main.buf, 4 .type .L.str.4,@object # @.str.4 .section .rodata.str1.1,"aMS",@progbits,1 .L.str.4: .asciz "Hello world: %s\n" .size .L.str.4, 17 .type .L.str.5,@object # @.str.5 .L.str.5: .asciz "6xxzcQMhb4WgKX0EUkwG747K" .size .L.str.5, 25 .ident "Fedora clang version 6.0.0 (trunk 311323) (based on LLVM 6.0.0svn-r311323)" .section ".note.GNU-stack","",@progbits
- 派生自LLVM的CallGraphSCCPass类,使得控制流图复杂化。
我在Linux进行了测试,大家可以在Mac上编译安装,期待大家的反馈,谢谢!
注:ARE(归属于 DragonEgg 子项目)使用GPLv2许可证。
Regards,
Leslie Zhai - a LLVM developer
Posts: 42
Participants: 5