文档章节

借助编译器阅读耗子叔6个变态的C语言Hello World程序

firebroo
 firebroo
发布于 2016/07/12 15:07
字数 1728
阅读 1886
收藏 1

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<stdio.h>
_____

这段代码初步一看,有点晕,但是如果耐心下来仔细读读,从一个安全从业者的角度来说,其实就是最为初级的加密,定义了一堆宏进行替换,很容易就可以把代码还原解读了,但是有一种更加快速不烧脑的方法,就是汇编。

gcc -std=c99 -S -o hello1.s -O2 -masm=intel -m64 hello1.c

汇编之后的结果:

hello1.s

	.file	"2.c"
	.intel_syntax noprefix
	.text
	.globl	main
main:
.LFB0:
	.cfi_startproc
	push	rbp
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	mov	rbp, rsp
	.cfi_def_cfa_register 6
	mov	edi, 72
	call	putchar
	mov	edi, 101
	call	putchar
	mov	edi, 108
	call	putchar
	mov	edi, 108
	call	putchar
	mov	edi, 111
	call	putchar
	mov	edi, 44
	call	putchar
	mov	edi, 32
	call	putchar
	mov	edi, 119
	call	putchar
	mov	edi, 111
	call	putchar
	mov	edi, 114
	call	putchar
	mov	edi, 108
	call	putchar
	mov	edi, 100
	call	putchar
	mov	edi, 33
	call	putchar
	mov	eax, 0
	pop	rbp
	.cfi_def_cfa 7, 8
	ret
	.cfi_endproc
.LFE0:
	.size	main, .-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<stdio.h>
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
	.globl	main
	.type	main, [[@function](http://my.oschina.net/u/569418)](http://my.oschina.net/u/569418)
main:
.LFB0:
	.cfi_startproc
	push	rbp
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	mov	rbp, rsp
	.cfi_def_cfa_register 6
	sub	rsp, 80
	mov	DWORD PTR [rbp-4], 0
	lea	rax, [rbp-80]
	mov	QWORD PTR [rbp-16], rax
	mov	rax, QWORD PTR [rbp-16]
	lea	rdx, [rax+4]
	mov	QWORD PTR [rbp-16], rdx
	mov	DWORD PTR [rax], 72
	mov	rax, QWORD PTR [rbp-16]
	lea	rdx, [rax+4]
	mov	QWORD PTR [rbp-16], rdx
	mov	edx, DWORD PTR [rbp-4]
	lea	ecx, [rdx+1]
	mov	DWORD PTR [rbp-4], ecx
	movsx	rdx, edx
	mov	edx, DWORD PTR [rbp-80+rdx*4]
	add	edx, 29
	mov	DWORD PTR [rax], edx
	mov	rax, QWORD PTR [rbp-16]
	lea	rdx, [rax+4]
	mov	QWORD PTR [rbp-16], rdx
	mov	edx, DWORD PTR [rbp-4]
	lea	ecx, [rdx+1]
	mov	DWORD PTR [rbp-4], ecx
	movsx	rdx, edx
	mov	edx, DWORD PTR [rbp-80+rdx*4]
	add	edx, 7
	mov	DWORD PTR [rax], edx
	mov	rax, QWORD PTR [rbp-16]
	lea	rdx, [rax+4]
	mov	QWORD PTR [rbp-16], rdx
	mov	edx, DWORD PTR [rbp-4]
	lea	ecx, [rdx+1]
	mov	DWORD PTR [rbp-4], ecx
	movsx	rdx, edx
	mov	edx, DWORD PTR [rbp-80+rdx*4]
	mov	DWORD PTR [rax], edx
	mov	rax, QWORD PTR [rbp-16]
	lea	rdx, [rax+4]
	mov	QWORD PTR [rbp-16], rdx
	mov	edx, DWORD PTR [rbp-4]
	lea	ecx, [rdx+1]
	mov	DWORD PTR [rbp-4], ecx
	movsx	rdx, edx
	mov	edx, DWORD PTR [rbp-80+rdx*4]
	add	edx, 3
	mov	DWORD PTR [rax], edx
	mov	rax, QWORD PTR [rbp-16]
	lea	rdx, [rax+4]
	mov	QWORD PTR [rbp-16], rdx
	mov	edx, DWORD PTR [rbp-4]
	lea	ecx, [rdx+1]
	mov	DWORD PTR [rbp-4], ecx
	movsx	rdx, edx
	mov	edx, DWORD PTR [rbp-80+rdx*4]
	sub	edx, 67
	mov	DWORD PTR [rax], edx
	mov	rax, QWORD PTR [rbp-16]
	lea	rdx, [rax+4]
	mov	QWORD PTR [rbp-16], rdx
	mov	edx, DWORD PTR [rbp-4]
	lea	ecx, [rdx+1]
	mov	DWORD PTR [rbp-4], ecx
	movsx	rdx, edx
	mov	edx, DWORD PTR [rbp-80+rdx*4]
	sub	edx, 12
	mov	DWORD PTR [rax], edx
	mov	rax, QWORD PTR [rbp-16]
	lea	rdx, [rax+4]
	mov	QWORD PTR [rbp-16], rdx
	mov	edx, DWORD PTR [rbp-4]
	lea	ecx, [rdx+1]
	mov	DWORD PTR [rbp-4], ecx
	movsx	rdx, edx
	mov	edx, DWORD PTR [rbp-80+rdx*4]
	add	edx, 87
	mov	DWORD PTR [rax], edx
	mov	rax, QWORD PTR [rbp-16]
	lea	rdx, [rax+4]
	mov	QWORD PTR [rbp-16], rdx
	mov	edx, DWORD PTR [rbp-4]
	lea	ecx, [rdx+1]
	mov	DWORD PTR [rbp-4], ecx
	movsx	rdx, edx
	mov	edx, DWORD PTR [rbp-80+rdx*4]
	sub	edx, 8
	mov	DWORD PTR [rax], edx
	mov	rax, QWORD PTR [rbp-16]
	lea	rdx, [rax+4]
	mov	QWORD PTR [rbp-16], rdx
	mov	edx, DWORD PTR [rbp-4]
	lea	ecx, [rdx+1]
	mov	DWORD PTR [rbp-4], ecx
	movsx	rdx, edx
	mov	edx, DWORD PTR [rbp-80+rdx*4]
	add	edx, 3
	mov	DWORD PTR [rax], edx
	mov	rax, QWORD PTR [rbp-16]
	lea	rdx, [rax+4]
	mov	QWORD PTR [rbp-16], rdx
	mov	edx, DWORD PTR [rbp-4]
	lea	ecx, [rdx+1]
	mov	DWORD PTR [rbp-4], ecx
	movsx	rdx, edx
	mov	edx, DWORD PTR [rbp-80+rdx*4]
	sub	edx, 6
	mov	DWORD PTR [rax], edx
	mov	rax, QWORD PTR [rbp-16]
	lea	rdx, [rax+4]
	mov	QWORD PTR [rbp-16], rdx
	mov	edx, DWORD PTR [rbp-4]
	lea	ecx, [rdx+1]
	mov	DWORD PTR [rbp-4], ecx
	movsx	rdx, edx
	mov	edx, DWORD PTR [rbp-80+rdx*4]
	sub	edx, 8
	mov	DWORD PTR [rax], edx
	mov	rax, QWORD PTR [rbp-16]
	lea	rdx, [rax+4]
	mov	QWORD PTR [rbp-16], rdx
	mov	edx, DWORD PTR [rbp-4]
	lea	ecx, [rdx+1]
	mov	DWORD PTR [rbp-4], ecx
	movsx	rdx, edx
	mov	edx, DWORD PTR [rbp-80+rdx*4]
	sub	edx, 67
	mov	DWORD PTR [rax], edx
	mov	rax, QWORD PTR [rbp-16]
	lea	rdx, [rax+4]
	mov	QWORD PTR [rbp-16], rdx
	mov	edx, DWORD PTR [rbp-4]
	movsx	rdx, edx
	mov	edx, DWORD PTR [rbp-80+rdx*4]
	sub	edx, 33
	mov	DWORD PTR [rax], edx
	sub	QWORD PTR [rbp-16], 4
	mov	rax, QWORD PTR [rbp-16]
	mov	eax, DWORD PTR [rax]
	mov	DWORD PTR [rbp-4], eax
	jmp	.L2
.L3:
	mov	eax, DWORD PTR [rbp-4]
	lea	edx, [rax+1]
	mov	DWORD PTR [rbp-4], edx
	cdqe
	mov	eax, DWORD PTR [rbp-80+rax*4]
	mov	edi, eax
	call	putchar
.L2:
	mov	eax, DWORD PTR [rbp-4]
	cdqe
	mov	eax, DWORD PTR [rbp-80+rax*4]
	cdqe
	test	rax, rax
	jne	.L3
	mov	eax, 0
	leave
	.cfi_def_cfa 7, 8
	ret
	.cfi_endproc
.LFE0:
	.size	main, .-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
	.globl	main
	.type	main, @function
main:
.LFB3:
	.cfi_startproc
	push	rbp
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	push	rbx
	.cfi_def_cfa_offset 24
	.cfi_offset 3, -24
	mov	edi, 72
	mov	ebx, 101
	sub	rsp, 72
	.cfi_def_cfa_offset 96
	mov	DWORD PTR [rsp], 72
	mov	DWORD PTR [rsp+4], 101
	lea	rbp, [rsp+8]
	mov	DWORD PTR [rsp+8], 108
	mov	DWORD PTR [rsp+12], 108
	mov	DWORD PTR [rsp+16], 111
	mov	DWORD PTR [rsp+20], 44
	mov	DWORD PTR [rsp+24], 32
	mov	DWORD PTR [rsp+28], 119
	mov	DWORD PTR [rsp+32], 111
	mov	DWORD PTR [rsp+36], 114
	mov	DWORD PTR [rsp+40], 108
	mov	DWORD PTR [rsp+44], 100
	mov	DWORD PTR [rsp+48], 33
	mov	DWORD PTR [rsp+52], 0
	jmp	.L2
	.p2align 4,,10
	.p2align 3
.L7:
	mov	eax, DWORD PTR [rbp+0]
	mov	edi, ebx
	add	rbp, 4
	mov	ebx, eax
.L2:
	mov	rsi, QWORD PTR stdout[rip]
	call	_IO_putc
	test	ebx, ebx
	jne	.L7
	add	rsp, 72
	.cfi_def_cfa_offset 24
	xor	eax, eax
	pop	rbx
	.cfi_def_cfa_offset 16
	pop	rbp
	.cfi_def_cfa_offset 8
	ret
	.cfi_endproc
.LFE3:
	.size	main, .-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段就不解析了,差不多。

© 著作权归作者所有

firebroo
粉丝 18
博文 28
码字总数 16581
作品 0
杭州
程序员
私信 提问
加载中

评论(3)

firebroo
firebroo 博主

引用来自“zhensuke”的评论

我想问下,是不是大多数语言都可以转换成汇编。
是。操作系统可以直接运行的二进制都可以转为汇编,你可以看看IDA,解释型的语法基本也有一种运行在自身虚拟机的字节码类汇编语法。
z
zhensuke
我想问下,是不是大多数语言都可以转换成汇编。
z
zhensuke
大神啊。求收留。
6个变态的C语言Hello World程序

下面的六个程序片段主要完成这些事情: 输出Hello, World 混乱C语言的源代码 下面的所有程序都可以在GCC下编译通过,只有最后一个需要动用C++的编译器g++才能编程通过。 hello1.c hello2.c ...

酸奶喝不完
2012/09/08
544
5
C语言程序结构「菜鸟入门篇」

C语言程序结构 C Hello World 实例 C 程序主要包括以下部分: 预处理器指令 函数 变量 语句 & 表达式 注释 让我们看一段简单的代码,可以输出单词 "Hello World": 实例 #includeintmain(){...

小辰带你看世界
2018/01/10
0
0
我所知道的C语言

C简介:C是一种通用的高级语言,最初是由丹尼斯.里奇在实验室为开发UNIX操作系统而设计的。C语言最早始于1972年在计算机上被首次实现。1978年制作了C语言的一个公开可用描述,现在被称为R&B...

crystalx静
2017/04/24
0
0
大数据哪里学习:程序C 语言的6种Hello World的写法

以下六个程序段主要完成以下工作: 输出 hello world 产生混乱的C语言源代码 下面的所有程序都可以在GCC下编译,大数据学习交流群:805017805,只有最后一个程序需要使用c++编译器G+。 hello1...

加米谷大数据
2018/07/11
9
0
经典中的博弈:第一章 C++的Hello,World!

经典中的博弈:第一章 C++的Hello,World! 摘要: 原创出处: http://www.cnblogs.com/Alandre/ 泥沙砖瓦浆木匠 希望转载,保留摘要,谢谢! “程序设计要通过编写程序的实践来学习”—Brian...

泥沙砖瓦浆木匠
2014/10/06
325
0

没有更多内容

加载失败,请刷新页面

加载更多

for循环

九九乘法表 示例:for(int i = 1; i <= 9; i++){ for (int j = 1; j <= i; j++) { // 每次开始i循环,j都会重新定义为j=1,然后开始循环计算 System.out.print(j +......

Shutting
14分钟前
3
0
小王子1

一定要帅! 韩国设计师品牌 insgram全世界得网红 韩国潮男穿搭 HM 找到穿衣服最好看的人,跟他比,比他好看。 在兴趣前,不要表现目的性,压力 关系是不热就冷的! 不喜欢压力,不喜欢负责任...

阿锋zxf
32分钟前
8
0
时间戳

1 loadTimeString(ts) { var d = new Date(); if (String(ts).length == 10) { d = new Date(ts * 1000); ......

东方巨人
34分钟前
5
0
Redis Cluster

Redis Cluster 集群 redis集群有以下几种方式 普通一主多从 普通一主多从+哨兵 cluster分片模式 一主多从 搭建方式网上很多,就不多描述了。 这种集群方式,一般master用作写,slave用做读,...

lazy~
35分钟前
8
0
 介绍一款优秀的通用管理权限快速开发框架

这是一套以权限管理为主的轻量化快速开发框架,配置有流程、专业表单、权限、app、企业微信等基础功能模块,在开发通用软件的效率上很有优势。 软件平台常用研发需求分析 《那些年我们一起做...

我想造火箭
51分钟前
12
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部