首页
课程
问答
CTF
社区
招聘
峰会
发现
排行榜
知识库
工具下载
看雪20年
看雪商城
证书查询
登录
注册
首页
社区
课程
招聘
发现
问答
CTF
排行榜
知识库
工具下载
峰会
看雪商城
证书查询
社区
CTF对抗
发新帖
35
14
花指令分析
发表于: 2024-7-31 23:26
13355
花指令分析
南行
3
2024-7-31 23:26
13355
>花指令:在代码中插入的不影响程序运行的垃圾指令(脏字节),让反编译器无法反编译起到混淆代码的作用。 ## 原理:反汇编算法的设计缺陷 反汇编算法主要可以分为两类:递归下降算法和线性扫描算法。 1. 线性扫描算法 线性扫描算法p1从程序的入口点开始反汇编,然后整个代码段进行扫描,反汇编扫描过程中所遇到的每条指令。线性扫描算法的缺点在于在冯诺依曼体系下,**无法区分数据和代码,从而导致将代码段中嵌入的数据误解释为指令的操作码,一致最后得到错误的反汇编结果**。 2. 递归下降 递归下降采取另外一种不同的方法来定位指令。递归下降算法强调控制流的概念。控制流根据一条指令是否被另一条指令引用来决定是否对其进行反汇编,遇到非控制转移指令时顺序进行反汇编,而遇到控制转移指令时则从转移地址处开始进行反汇编。通过构造**必然条件**或者**互补条件**,使得反汇编出错。 ## 关于花指令的构造 花指令的名言: > 构造永恒跳转,插入垃圾数据 我们通过在代码中内嵌汇编指令实现插入花指令。在不同的编译器中我们嵌入汇编的格式也不同。 主要的编译器分别为msvc和gcc,我们每个例子都会写出两种不同编译器的实现方法。 **msvc内嵌汇编** ```c #include<stdio.h> int main() { #嵌入汇编代码 __asm { jmp s; #emit指令用于插入垃圾数据 _emit 0xe9; s: } printf("hello world!\n"); return 0; } ``` **gcc内嵌汇编** ```c #include<stdio.h> int main() { #gcc编译器内嵌汇编 __asm__ __volatile__ ( "jmp s\n\t" // 跳转指令,跳转到s标签 ".byte 0xe9\n\t" // 插入字节0xC7 "s:\n\t" // s标签 ); printf("hello world!\n"); return 0; } ``` **常用的脏字节编码** 构造跳转使插入的垃圾数据不被执行来欺骗反编译器。 我们将插入的垃圾数据称为脏字节。 下面就是我们插入花指令常用的脏字节。 ``` call immed16 ----> E8 // 3字节指令,immed16为2字节,代表跳转指令的目的地址与下一条指令地址的距离 call immed32 ----> 9A // 5字节指令,immed32为4字节,代表跳转指令的目的地址与下一条指令地址的距离 jmp immed8 ----> EB jmp immed16 ----> E9 jmp immed32 ----> EA loop immed8 ----> E2 ret ----> C2 retn ----> C3 ``` 接下来我们介绍常见的花指令实现方式和清除方法。 ### 简单jmp指令 ``` jmp s _emit 0xe9; s: ``` 这种 jmp 单次跳转只能骗过线性扫描算法,会被ida识别(递归下降)。 #### 实现 **msvc 编译器实现** ```c #include<stdio.h> int main() { __asm { jmp s; _emit 0xe9; s: } printf("hello world!\n"); return 0; } ``` **gcc 编译器实现** ```c #include<stdio.h> int main() { __asm__ __volatile__ ( "jmp s\n\t" ".byte 0xe9\n\t" "s:\n\t" ); printf("hello world!\n"); return 0; } ``` #### 分析 我们将程序编译后利用ida打开查看 直接f5成功  查看汇编代码,发现了我们插入的花指令。 很明显这种花指令无法骗过ida。  ### **多层跳转** ``` __asm{ jmp s1; _emit 68h; s1: jmp s2; _emit 0cdh; _emit 20h; s2: jmp s3; _emit 0e8h; s3: } ``` 和单次跳转一样,这种也会被ida识别。 #### 实现 **msvc 编译器实现** ```c #include<stdio.h> int main() { __asm { jmp s1; _emit 0xe9; s1: jmp s2; s2: jmp s3; s3: } printf("hello world!\n"); return 0; } ``` **gcc 编译器实现** ```c #include<stdio.h> int main(){ __asm__ __volatile__( "jmp s1\n\t" ".byte 0xe9\n\t" "s1:\n\t" "jmp s2\n\t" ".byte 0x68\n\t" "s2:\n\t" "jmp s3\n\t" ".byte 0x20\n\t" "s3:\n\t" ); printf("hello world\n"); return 0; } ``` #### 分析 同样ida打开成功f5。  查看汇编代码,查看我们插入的花指令。 显然这种花指令也无法骗过ida。  ### jnx和jx互补跳转 ``` __asm { jz s; jnz s; _emit 0xC7; s: ``` 这种花指令去除方式也很简单,特征也很明显,因为是近跳转,所以ida分析的时候会分析出jz或者jnz会跳转几个字节,这个时候我们就可得到垃圾数据的长度,将该长度字节的数据全部nop掉即可解混淆。 #### 实现 **msvc 编译器实现** ```c #include<stdio.h> int main(){ __asm{ jz s: jnz s: _emit 0xe9; s: } printf("hello world!\n"); return 0; } ``` **gcc 编译器实现** ```c #include <stdio.h> int main() { printf("Before jump and emit instructions\n"); // 插入花指令 __asm__ __volatile__ ( "jz s\n\t" // 跳转指令 "jnz s\n\t" // 跳转指令 ".byte 0xC7\n\t" // 插入字节0xC7 "s:\n\t" // 标签 ); printf("hello world!\n"); return 0; } ``` #### 分析 ida打开文件报红,f5反编译不成功。 很明显这种花指令骗过了ida。 接下来我们进行去除。  看到条件跳转到s,则中间的全部为垃圾数据。将其全部nop掉。  选中nop掉的数据的那一行,按快捷键c将数据解释为代码。 然后选中main函数头部,按p创建函数。 然后即可f5反编译。  ### 跳转指令构造花指令 ``` __asm { push ebx; xor ebx, ebx; test ebx, ebx; jnz s1; jz s2; s1: _emit 0xC7; s2: pop ebx; } ``` #### 实现 **msvc 编译器实现** ```c #include<stdio.h> int main(){ __asm{ push ebx; xor ebx,ebx; test ebx,ebx; jnz s1: jz s2: s1 _emit 0xe9; s2: pop ebx; } printf("hello world!\n"); return 0; } ``` **gcc 编译器实现** ```c #include <stdio.h> int main() { printf("Before jump and emit instructions\n"); // 插入花指令 __asm__ __volatile__ ( "pushq %rbx\n\t" // 跳转指令 "xor %rbx,%rbx\n\t" // 跳转指令 "test %rbx,%rbx\n\t" // 插入字节0xC7 "jz s1\n\t" "jnz s2\n\t" "s1:\n\t" ".byte 0xc7\n\t" "s2:\n\t" "popq %rbx\n\t" ); printf("hello world!\n"); return 0; } ``` 很明显,先对ebx进行xor之后,再进行test比较,zf标志位肯定为1,就肯定执行跳转 s1,也就是说中间0xC7永远不会执行。 不过这种一定要注意:记着保存ebx的值先把ebx压栈,最后在pop出来。 解混淆的时候也需要稍加注意,需要分析一下哪里是哪里是真正会跳到的位置,然后将垃圾数据nop掉,本质上和前面几种没什么不同。 #### 分析 ida打开程序无法反编译,可以看到我们插入的花指令。  根据汇编代码判断哪里s1永远不会执行。 然后将插入的垃圾数据nop掉。 之后选中nop掉的数据的那一行,按快捷键c将数据解释为代码。 然后选中main函数头部,按p创建函数。 然后即可f5反编译。 ### **call&ret构造花指令** ``` __asm { call LABEL9; _emit 0x83; LABEL9: add dword ptr ss : [esp] , 8; ret; __emit 0xF3; } ``` call之类的本质:push 函数返回地址然后 jmp 函数地址 ret指令的本质:pop eip 代码中的esp存储的是函数返回地址,对\[esp]+8,就是函数的返回地址+8,正好盖过代码中的函数指令和垃圾数据。 #### 实现 **msvc 编译器实现** ```c #include<stdio.h> int main(){ __asm{ call s; _emit 0x83; s: add dword ptr ss:[esp],8; ret; _emit 0xf3; } printf("hello world!\n"); return 0; } ``` **gcc 编译器实现** ```c #include <stdio.h> int main() { printf("Before jump and emit instructions\n"); // 插入花指令 __asm__ __volatile__ ( "call s\n\t" ".byte 0x83\n\t" "s:\n\t" "addq 8,(%rsp)\n\t" "ret\n\t" ".byte 0xf3\n\t" ); printf("hello world!\n"); return 0; } ``` #### 分析 ida打开看到我们插入的花指令,  分析代码,call s直接跳转到s并将下一行代码入栈。 则0x83h永远不会被执行,并且将其地址入栈。 add指令将栈顶数据即0x83h地址加上8,则栈上地址为0x115e。 经过retn指令后,执行流直接跳到0x48h。 则不被执行的0x83和0xf3h都是垃圾数据,将它们nop即可。 ### 汇编指令共用opcode jmp的条指令是inc eax的第一个字节,inc eax和dec eax低效影响。这种共用opcode确实比较麻烦。   #### 实现 **msvc 编译器实现** ```c #include<stdio.h> int main(){ __asm{ _emit 0xeb,0xff,0xc0,0x48 } printf("hello world!\n"); return 0; } ``` **gcc 编译器实现** ```c #include <stdio.h> int main() { // 插入花指令 __asm__ __volatile__ ( ".byte 0xeb,0xff,0xc0,0x48\n\t" ); printf("hello world!\n"); } ``` #### 分析 这里我们先运行一下程序,发现程序只是用于输出`hello world!`。 通过汇编代码逻辑分析我们发现`jmp`指令跳转到了`loc_1151`标签的后一字节处即`0x1152`。  我们首先通过快捷键`u`将`loc_1151`标签处的汇编指令解释为机器码。  然后先将`0x1152`后面的汇编指令解释为机器码,之后在`0x1152`处按快捷键`c`将其解释为汇编代码。 可以看到现在的汇编代码符合程序功能,我们通过此判断`0xebh`到`0x48h`都是花指令。  我们重新将他们通过快捷键`u`解释为机器码,然后在`0x48h`的下面即`0x1154`处按快捷键`c`将它们解释为汇编代码。  然后将`0xebh`到`0x48h`全部`nop`掉。  之后选中`main`函数头部,按快捷键`p`创建函数。 然后即可`f5`反编译。  ## 快速插入花指令 我们可以通过将花指令定义为宏来在代码中快速插入花指令。 ``` #include <stdio.h> #include <stdlib.h> #define FLOWER \ __asm__ __volatile__ ( \ "jz s\n\t" \ "jnz s\n\t" \ ".byte 0xC7\n\t" \ "s:\n\t" \ ) int main(){ FLOWER; printf("hello world\n"); return 0; } ``` ## 脚本清除花指令 除汇编指令共用之外,上面有3个类别花指令ida无法正常识别 1. 互补条件跳转(比较好处理) 2. 永真条件跳转(各种永真条件比较难匹配) 3. call&ret跳转(比较难处理) 所以就只对第一种jnx和jx的花指令进行自动化处理 所有的跳转指令,互补跳转指令只有最后一个不同 ``` 70 <–> JO(O标志位为1跳转) 71 <–> JNO 72 <–> JB/JNAE/JC 73 <–> JNB/JAE/JNC 74 <–> JZ/JE 75 <–> JNZ/JNE 76 <–> JBE/JNA 77 <–> JNBE/JA 78 <–> JS 79 <–> JNS 7A <–> JP/JPE 7B <–> JNP/JPO 7C <–> JL/JNGE 7D <–> JNL/JGE 7E <–> JLE/JNG 7F <–> JNLE/JG ``` 抄大佬的代码 ```python from ida_bytes import get_bytes,patch_bytes start= 0x401000#start addr end = 0x422000 buf = get_bytes(start,end-start) def patch_at(p,ln): global buf buf = buf[:p]+b"\x90"*ln+buf[p+ln:] fake_jcc=[] for opcode in range(0x70,0x7f,2): pattern = chr(opcode)+"\x03"+chr(opcode|1)+"\x01" fake_jcc.append(pattern.encode()) pattern = chr(opcode|1)+"\x03"+chr(opcode)+"\x01" fake_jcc.append(pattern.encode()) print(fake_jcc) for pattern in fake_jcc: p = buf.find(pattern) while p != -1: patch_at(p,5) p = buf.find(pattern,p+1) patch_bytes(start,buf) print("Done") ``` ## 后言 > 参考链接:<a href="elink@876K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6%4N6%4N6Q4x3X3g2S2L8Y4q4#2j5h3&6C8k6g2)9J5k6h3y4G2L8g2)9J5c8Y4m8G2M7%4c8Q4x3V1k6A6k6q4)9J5c8U0t1K6y4U0b7&6x3q4)9J5x3$3R3J5i4K6u0V1x3l9`.`.">花指令总结-安全客 - 安全资讯平台 (anquanke.com)</a> > > 参考链接:<a href="elink@d8aK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6T1L8r3!0Y4i4K6u0W2j5%4y4V1L8W2)9J5k6h3&6W2N6q4)9J5c8X3q4T1k6h3I4Q4y4h3k6T1K9h3N6Q4y4h3k6^5N6g2)9J5c8X3q4J5N6r3W2U0L8r3g2Q4x3V1k6V1k6i4c8S2K9h3I4K6i4K6u0r3x3e0p5%4z5e0t1%4y4U0M7@1">逆向分析基础 --- 花指令实现及清除_jmp花指令逆向-CSDN博客</a> > > 参考链接:<a href="elink@401K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6T1L8r3!0Y4i4K6u0W2j5%4y4V1L8W2)9J5k6h3&6W2N6q4)9J5c8W2y4U0K9i4g2J5k6r3q4W2i4K6u0r3j5i4u0@1K9h3y4D9k6g2)9J5c8X3c8W2N6r3q4A6L8s2y4Q4x3V1j5I4x3K6x3^5z5e0f1J5z5o6c8Q4x3@1k6G2M7s2y4Q4y4h3k6J5k6i4q4#2k6i4y4@1i4K6g2X3L8h3W2K6j5#2)9K6c8q4)9J5y4e0N6n7i4K6t1#2x3U0u0J5k6i4q4#2k6i4y4@1i4K6t1#2y4f1k6A6k6q4)9J5y4e0t1J5i4K6t1#2x3@1q4Q4x3U0f1J5x3U0p5%4x3U0l9#2x3U0x3$3x3K6l9I4y4U0R3H3x3o6p5^5x3U0M7@1z5e0M7$3y4W2)9J5y4e0t1J5i4K6t1#2x3V1y4Q4x3U0f1J5x3Y4y4U0L8g2)9J5y4e0t1J5i4K6t1#2x3@1q4Q4x3U0f1J5x3U0t1H3x3e0b7H3y4K6p5K6i4K6u0W2x3e0x3H3x3e0l9J5x3K6x3@1i4K6u0W2M7r3y4Q4x3U0f1#2c8X3u0D9L8$3N6Q4x3X3g2Q4x3U0f1J5x3W2)9J5y4e0N6p5i4K6t1$3M7X3g2I4N6h3g2K6N6q4)9#2k6X3W2V1i4K6y4p5x3e0M7J5x3o6f1J5x3K6j5K6x3o6p5$3z5o6l9H3x3e0R3J5y4K6b7&6y4K6j5$3i4K6t1$3j5X3W2*7i4K6g2X3K9h3c8Q4x3@1b7H3i4K6t1$3N6i4c8E0i4K6g2X3L8h3g2V1K9i4g2E0i4K6y4p5k6r3W2K6N6s2u0A6j5Y4g2@1k6g2)9J5k6i4m8U0i4K6g2X3M7$3g2S2M7X3y4Z5i4K6g2X3M7X3g2K6N6h3I4@1i4K6u0W2L8X3!0F1k6g2)9J5k6s2c8S2M7$3E0Q4x3X3c8T1L8r3!0Y4i4K6u0V1x3W2)9%4c8h3u0D9L8$3N6Q4y4@1g2X3K9i4u0K6N6q4)9#2k6Y4u0S2L8X3E0Q4y4h3k6W2j5%4m8E0i4K6g2X3N6U0q4Q4y4@1g2J5j5h3&6C8i4K6g2X3N6U0x3I4i4K6g2X3k6h3y4H3L8g2)9J5k6o6q4Q4x3X3b7I4x3K6x3^5z5e0f1J5z5o6c8Q4x3X3c8F1N6h3I4D9i4K6u0V1L8Y4g2D9L8q4)9J5k6h3&6G2L8X3g2U0j5i4y4W2i4K6t1$3N6i4c8E0i4K6g2X3N6r3g2J5L8g2)9K6c8q4!0q4z5q4)9^5b7g2!0n7x3g2!0q4y4W2)9^5b7#2)9^5y4#2!0q4y4q4!0n7b7W2!0m8y4l9`.`.">CTF逆向Reverse 花指令介绍 and NSSCTF靶场入门题目复现_花指令原理ctf-CSDN博客</a>
登录后可查看完整内容
冰与火的战歌:Windows内核攻防实战高级班!从零到实战,融合AI与Windows内核攻防全技术栈,打造具备自动化能力的内核开发高手。
最后于
2025-11-9 18:22 被南行编辑 ,原因: 修改
#Reverse
收藏
・
35
点赞
・
14
打赏
分享
分享到微信
分享到QQ
分享到微博
赞赏记录
参与人
雪币
留言
时间
mb_ovmxbmhd
你的帖子非常有用,感谢分享!
2026-9-12 08:30
ra1ny
+1
你的分享对大家帮助很大,非常感谢!
2026-1-15 14:18
_Alberto_
谢谢你的细致分析,受益匪浅!
2025-2-17 20:09
PLEBFE
看雪因你而更加精彩!
2024-9-25 02:05
Ally Switch
+1
你的帖子非常有用,感谢分享!
2024-8-12 16:44
Bcdlbgm
你的分享对大家帮助很大,非常感谢!
2024-8-6 10:27
asciibase64
你的帖子非常有用,感谢分享!
2024-8-3 21:47
Y6blNU1L
这个讨论对我很有帮助,谢谢!
2024-8-3 10:02
Oday小斯
谢谢你的细致分析,受益匪浅!
2024-8-2 23:04
菜小基
为你点赞~
2024-8-2 16:00
你瞒我瞒
为你点赞~
2024-8-2 10:33
yp太阳神
感谢你的积极参与,期待更多精彩内容!
2024-8-2 09:38
jmpcall
你的帖子非常有用,感谢分享!
2024-8-2 09:28
养只猫不好么
为你点赞~
2024-8-1 16:06
查看更多
赞赏
×
1 雪花
5 雪花
10 雪花
20 雪花
50 雪花
80 雪花
100 雪花
150 雪花
200 雪花
支付方式:
微信支付
赞赏留言:
快捷留言
感谢分享~
精品文章~
原创内容~
精彩转帖~
助人为乐~
感谢分享~
最新回复
(
2
)
mb_ldbucrik
雪 币:
6
能力值:
( LV1,RANK:0 )
在线值:
发帖
0
回帖
691
粉丝
7
关注
私信
mb_ldbucrik
2
楼
跟着大佬学习
2024-8-1 09:59
0
lingyi223
雪 币:
1061
活跃值:
(3285)
能力值:
( LV4,RANK:40 )
在线值:
发帖
6
回帖
35
粉丝
11
关注
私信
lingyi223
3
楼
.text:004118C7
汇编指令共用opcode:
.text:004118C7 __$EncStackInitEnd_1: ; CODE XREF: _main:__$EncStackInitEnd_1↑j
.text:004118C7 EB FF jmp short near ptr __$EncStackInitEnd_1+1
.text:004118C7 ; -----------------------------------------------------------------
$EncStackInitEnd_1+1跳转的是ff,所以eb就是垃圾指令,然后吧eb手动nop掉就行了
2025-11-9 14:24
1
游客
登录
|
注册
方可回帖
回帖
表情
雪币赚取及消费
高级回复
返回
南行
3
6
发帖
5
回帖
140
RANK
关注
私信
他的文章
[原创]Linux内核modprobe_path覆盖利用技术
19219
[原创]RC4算法逆向分析
12405
[原创]SMC自修改代码
12802
花指令分析
13355
[原创Linux程序保护机制
7236
关于我们
联系我们
企业服务
看雪公众号
专注于PC、移动、智能设备安全研究及逆向工程的开发者社区
看原图
赞赏
×
雪币:
+
留言:
快捷留言
为你点赞!
返回
顶部