hello1.c
#define _________ }
#define ________ putchar
#define _______ main
#define _(a) ________(a);
#define ______ _______(){
#define __ ______ _(0x48)_(0x65)_(0x6C)_(0x6C)
#define ___ _(0x6F)_(0x2C)_(0x20)_(0x77)_(0x6F)
#define ____ _(0x72)_(0x6C)_(0x64)_(0x21)
#define _____ __ ___ ____ _________
#include
_____
这段代码初步一看,有点晕,但是如果耐心下来仔细读读,从一个安全从业者的角度来说,其实就是最为初级的加密,定义了一堆宏进行替换,很容易就可以把代码还原解读了,但是有一种更加快速不烧脑的方法,就是汇编。
gcc -std=c99 -S -o hello1.s -O2 -masm=intel -m64 hello1.c
汇编之后的结果:
hello1.s
.file"2.c"
.intel_syntax noprefix
.text
.globlmain
main:
.LFB0:
.cfi_startproc
pushrbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movrbp, rsp
.cfi_def_cfa_register 6
movedi, 72
callputchar
movedi, 101
callputchar
movedi, 108
callputchar
movedi, 108
callputchar
movedi, 111
callputchar
movedi, 44
callputchar
movedi, 32
callputchar
movedi, 119
callputchar
movedi, 111
callputchar
movedi, 114
callputchar
movedi, 108
callputchar
movedi, 100
callputchar
movedi, 33
callputchar
moveax, 0
poprbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.sizemain, .-main
.ident"GCC: (GNU) 4.9.2 20150212 (Red Hat 4.9.2-6)"
.section.note.GNU-stack,"",@progbits
如果懂汇编,这很容易读,不懂的也没事,简单的说就是,把字符串"hello,world!"对应的ascii码逐一的送入edi寄存器,64位操作系统函数的前留给参数分别保存在rdi,rsi,rdx,rcx,r8,r9,之后才是栈,压入之后,调用putchar函数输出字符到stdout。
再来看hello2.c
#include
int main(){
int x=0,y[14],*z=&y;*(z++)=0x48;*(z++)=y[x++]+0x1D;
*(z++)=y[x++]+0x07;*(z++)=y[x++]+0x00;*(z++)=y[x++]+0x03;
*(z++)=y[x++]-0x43;*(z++)=y[x++]-0x0C;*(z++)=y[x++]+0x57;
*(z++)=y[x++]-0x08;*(z++)=y[x++]+0x03;*(z++)=y[x++]-0x06;
*(z++)=y[x++]-0x08;*(z++)=y[x++]-0x43;*(z++)=y[x]-0x21;
x=*(--z);while(y[x]!=NULL)putchar(y[x++]);
}
这一段代码没用使用宏,主要是靠运算来混淆,也是看的头晕,我一直感觉加一减一这种问题很容易导致出错。。如果依然使用上面的方法通过gcc的O0不优化得到的汇编代码:
hello2.s
.file"2.c"
.intel_syntax noprefix
.text
.globlmain
.typemain, [[@function](http://my.oschina.net/u/569418)](http://my.oschina.net/u/569418)
main:
.LFB0:
.cfi_startproc
pushrbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movrbp, rsp
.cfi_def_cfa_register 6
subrsp, 80
movDWORD PTR [rbp-4], 0
learax, [rbp-80]
movQWORD PTR [rbp-16], rax
movrax, QWORD PTR [rbp-16]
leardx, [rax+4]
movQWORD PTR [rbp-16], rdx
movDWORD PTR [rax], 72
movrax, QWORD PTR [rbp-16]
leardx, [rax+4]
movQWORD PTR [rbp-16], rdx
movedx, DWORD PTR [rbp-4]
leaecx, [rdx+1]
movDWORD PTR [rbp-4], ecx
movsxrdx, edx
movedx, DWORD PTR [rbp-80+rdx*4]
addedx, 29
movDWORD PTR [rax], edx
movrax, QWORD PTR [rbp-16]
leardx, [rax+4]
movQWORD PTR [rbp-16], rdx
movedx, DWORD PTR [rbp-4]
leaecx, [rdx+1]
movDWORD PTR [rbp-4], ecx
movsxrdx, edx
movedx, DWORD PTR [rbp-80+rdx*4]
addedx, 7
movDWORD PTR [rax], edx
movrax, QWORD PTR [rbp-16]
leardx, [rax+4]
movQWORD PTR [rbp-16], rdx
movedx, DWORD PTR [rbp-4]
leaecx, [rdx+1]
movDWORD PTR [rbp-4], ecx
movsxrdx, edx
movedx, DWORD PTR [rbp-80+rdx*4]
movDWORD PTR [rax], edx
movrax, QWORD PTR [rbp-16]
leardx, [rax+4]
movQWORD PTR [rbp-16], rdx
movedx, DWORD PTR [rbp-4]
leaecx, [rdx+1]
movDWORD PTR [rbp-4], ecx
movsxrdx, edx
movedx, DWORD PTR [rbp-80+rdx*4]
addedx, 3
movDWORD PTR [rax], edx
movrax, QWORD PTR [rbp-16]
leardx, [rax+4]
movQWORD PTR [rbp-16], rdx
movedx, DWORD PTR [rbp-4]
leaecx, [rdx+1]
movDWORD PTR [rbp-4], ecx
movsxrdx, edx
movedx, DWORD PTR [rbp-80+rdx*4]
subedx, 67
movDWORD PTR [rax], edx
movrax, QWORD PTR [rbp-16]
leardx, [rax+4]
movQWORD PTR [rbp-16], rdx
movedx, DWORD PTR [rbp-4]
leaecx, [rdx+1]
movDWORD PTR [rbp-4], ecx
movsxrdx, edx
movedx, DWORD PTR [rbp-80+rdx*4]
subedx, 12
movDWORD PTR [rax], edx
movrax, QWORD PTR [rbp-16]
leardx, [rax+4]
movQWORD PTR [rbp-16], rdx
movedx, DWORD PTR [rbp-4]
leaecx, [rdx+1]
movDWORD PTR [rbp-4], ecx
movsxrdx, edx
movedx, DWORD PTR [rbp-80+rdx*4]
addedx, 87
movDWORD PTR [rax], edx
movrax, QWORD PTR [rbp-16]
leardx, [rax+4]
movQWORD PTR [rbp-16], rdx
movedx, DWORD PTR [rbp-4]
leaecx, [rdx+1]
movDWORD PTR [rbp-4], ecx
movsxrdx, edx
movedx, DWORD PTR [rbp-80+rdx*4]
subedx, 8
movDWORD PTR [rax], edx
movrax, QWORD PTR [rbp-16]
leardx, [rax+4]
movQWORD PTR [rbp-16], rdx
movedx, DWORD PTR [rbp-4]
leaecx, [rdx+1]
movDWORD PTR [rbp-4], ecx
movsxrdx, edx
movedx, DWORD PTR [rbp-80+rdx*4]
addedx, 3
movDWORD PTR [rax], edx
movrax, QWORD PTR [rbp-16]
leardx, [rax+4]
movQWORD PTR [rbp-16], rdx
movedx, DWORD PTR [rbp-4]
leaecx, [rdx+1]
movDWORD PTR [rbp-4], ecx
movsxrdx, edx
movedx, DWORD PTR [rbp-80+rdx*4]
subedx, 6
movDWORD PTR [rax], edx
movrax, QWORD PTR [rbp-16]
leardx, [rax+4]
movQWORD PTR [rbp-16], rdx
movedx, DWORD PTR [rbp-4]
leaecx, [rdx+1]
movDWORD PTR [rbp-4], ecx
movsxrdx, edx
movedx, DWORD PTR [rbp-80+rdx*4]
subedx, 8
movDWORD PTR [rax], edx
movrax, QWORD PTR [rbp-16]
leardx, [rax+4]
movQWORD PTR [rbp-16], rdx
movedx, DWORD PTR [rbp-4]
leaecx, [rdx+1]
movDWORD PTR [rbp-4], ecx
movsxrdx, edx
movedx, DWORD PTR [rbp-80+rdx*4]
subedx, 67
movDWORD PTR [rax], edx
movrax, QWORD PTR [rbp-16]
leardx, [rax+4]
movQWORD PTR [rbp-16], rdx
movedx, DWORD PTR [rbp-4]
movsxrdx, edx
movedx, DWORD PTR [rbp-80+rdx*4]
subedx, 33
movDWORD PTR [rax], edx
subQWORD PTR [rbp-16], 4
movrax, QWORD PTR [rbp-16]
moveax, DWORD PTR [rax]
movDWORD PTR [rbp-4], eax
jmp.L2
.L3:
moveax, DWORD PTR [rbp-4]
leaedx, [rax+1]
movDWORD PTR [rbp-4], edx
cdqe
moveax, DWORD PTR [rbp-80+rax*4]
movedi, eax
callputchar
.L2:
moveax, DWORD PTR [rbp-4]
cdqe
moveax, DWORD PTR [rbp-80+rax*4]
cdqe
testrax, rax
jne.L3
moveax, 0
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.sizemain, .-main
.ident"GCC: (GNU) 4.9.2 20150212 (Red Hat 4.9.2-6)"
.section.note.GNU-stack,"",@progbits
可以看到,挺难读的。。其实可以使用O2优化,执行:
gcc -std=c99 -S -o hello2.s -O2 -masm=intel -m64 hello2.c
.file"2.c"
.intel_syntax noprefix
.section.text.unlikely,"ax",@progbits
.LCOLDB0:
.section.text.startup,"ax",@progbits
.LHOTB0:
.p2align 4,,15
.globlmain
.typemain, @function
main:
.LFB3:
.cfi_startproc
pushrbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
pushrbx
.cfi_def_cfa_offset 24
.cfi_offset 3, -24
movedi, 72
movebx, 101
subrsp, 72
.cfi_def_cfa_offset 96
movDWORD PTR [rsp], 72
movDWORD PTR [rsp+4], 101
learbp, [rsp+8]
movDWORD PTR [rsp+8], 108
movDWORD PTR [rsp+12], 108
movDWORD PTR [rsp+16], 111
movDWORD PTR [rsp+20], 44
movDWORD PTR [rsp+24], 32
movDWORD PTR [rsp+28], 119
movDWORD PTR [rsp+32], 111
movDWORD PTR [rsp+36], 114
movDWORD PTR [rsp+40], 108
movDWORD PTR [rsp+44], 100
movDWORD PTR [rsp+48], 33
movDWORD PTR [rsp+52], 0
jmp.L2
.p2align 4,,10
.p2align 3
.L7:
moveax, DWORD PTR [rbp+0]
movedi, ebx
addrbp, 4
movebx, eax
.L2:
movrsi, QWORD PTR stdout[rip]
call_IO_putc
testebx, ebx
jne.L7
addrsp, 72
.cfi_def_cfa_offset 24
xoreax, eax
poprbx
.cfi_def_cfa_offset 16
poprbp
.cfi_def_cfa_offset 8
ret
.cfi_endproc
.LFE3:
.sizemain, .-main
.section.text.unlikely
.LCOLDE0:
.section.text.startup
.LHOTE0:
.ident"GCC: (GNU) 4.9.2 20150212 (Red Hat 4.9.2-6)"
.section.note.GNU-stack,"",@progbits
这次代码量少了很多,好读多了,大概意思就是把hello,world!的ascii码送入rsp栈中,之后跳到L2,L2中逻辑是先调用系统调用_IO_PUTC输入rdi中的字符到stdout中,之后使用test指令,测试ebx是否为零,jnz和jne效果等同,根据ZF标志位来跳转,如果不为零,跳转到L7,直到遇到字符串结尾字符'\0',ZF=0,jne .L7不成立往下执行程序结束。
其余的4段就不解析了,差不多。