Quantcast
Channel: Essence Sharing | 干货分享 - iOSRE
Viewing all articles
Browse latest Browse all 301

Llvm “防”反向 pass

$
0
0

@xiangzhai wrote:

Hi Hackers,

反向工程、防反向是永恒的博弈艺术 :slight_smile:

引子:我这两天学习如何编写一个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

我在Linux进行了测试,大家可以在Mac上编译安装,期待大家的反馈,谢谢!

注:ARE(归属于 DragonEgg 子项目)使用GPLv2许可证。

Regards,
Leslie Zhai - a LLVM developer

Posts: 42

Participants: 5

Read full topic


Viewing all articles
Browse latest Browse all 301

Trending Articles