duangsuse::Echo
Radare2 反汇编出来的东西 size 居然是错的... emmmm 害得我又熬夜了这么久
那个 ecx 偏移量运行时会取一个双字(long int)的(本地变量 [ebp-0xe])数据到寄存器,然而其实只给了它(这个本地变量) 4 字节的空间!结果就是它会把 0x0008 后面的 0x0064 也取到一起,加到
char *s 上面就是个无效偏移量 unmapped memory,直接段错误
duangsuse::Echo
Radare2 反汇编出来的东西 size 居然是错的... emmmm 害得我又熬夜了这么久
根本不是一个双字吧!就是一个字的数据而已
duangsuse::Echo
cooltok.zip
byte = 8
halfword = 16
word = 32
size = 32
dword = 64
byte char
size char *
dword double
word float
word int
halfword int16_t
word int32_t
dword int64_t
byte int8_t
dowrd long
dword long long
halfword short
size size_t
halfword uint16_t
word uint32_t
dword uint64_t
byte uint8_t
byte unsigned char
word unsigned int
halfword unsigned short
size void *
halfword = 16
word = 32
size = 32
dword = 64
byte char
size char *
dword double
word float
word int
halfword int16_t
word int32_t
dword int64_t
byte int8_t
dowrd long
dword long long
halfword short
size size_t
halfword uint16_t
word uint32_t
dword uint64_t
byte uint8_t
byte unsigned char
word unsigned int
halfword unsigned short
size void *
duangsuse::Echo
🤔 r2 明明知道一个 int 只有 word 那么长,为什么还要上 dword address 呢...
我没想到的是 i686 里寄存器看起来也有一个双字么... 🤔
我以为 32 位的意思是寄存器都是 32 位的,可是 edb 里却有 8 个 16 进制数位...
我以为 32 位的意思是寄存器都是 32 位的,可是 edb 里却有 8 个 16 进制数位...
duangsuse::Echo
我没想到的是 i686 里寄存器看起来也有一个双字么... 🤔 我以为 32 位的意思是寄存器都是 32 位的,可是 edb 里却有 8 个 16 进制数位...
用 radare2 的其他反汇编模式看看,发现 64 位模式下只是 ebp 改成了 rbp,这... 🤔
我只是想上动态分析看汇编啊...
我只是想上动态分析看汇编啊...
duangsuse::Echo
这就是一个正确的栗子,它给栈帧分配的是两个 dword 的空间,而上面那个是没有完成分配的任务,居然只给 64 位的东西分配 32 位的空间,读写都会冲突
执行时是怎么样的呢? 🤔(当然这里可能不严谨,不过也够了,反正大家很多人连 CDEF 系统栈是怎么维护的都不知道,也算是科普一下)
我们的 caller 叫做 main,它执行如下代码以调用我们的子程序 bd:
然后机器开始解释执行我们的程序逻辑:
==
; eip = *__x86_get_pc_thunk_bx
(其实就是拿到位于 .text 段的 ip 指针,也就是
(我们要重新用汇编重写的时候必须也重写这种 ebx 偏移量,把对它们的使用替换成 .rodata 段实际的偏移地址,NASM 可以帮我们做这件事,直接
; eip = *bd
; eax = *bd+5i
== 然后我们又回到了自己的程序
; GCC(GNU Compiler Collection) 4.9 是相当老的编译器了,不要忘记现在 GCC 都出 8 了
eax = my_arg2
eax = my_arg1
🤔所以,我们为什么要多分配这么多无用的东西?浪费了一个双字的空间(虽然 mov subarg2 的时候可能溢出到别的存储单元)
🤔
一瞬返回
最后 main 收拾调用现场
== main+???
对 bd 的调用就完成了(迫真)
我们的 caller 叫做 main,它执行如下代码以调用我们的子程序 bd:
sub esp, (2*4)<sp> [....] [....] |*****
mov ecx, ; buffer
; ecx = (char *) buffermov [esp+4], "SGVsbG8K"
<sp> [....] [*"SGV....] |*****mov [esp], ecx
<sp> [*buffer] [*"SGV....] |*****call bd
; eip = *bd然后机器开始解释执行我们的程序逻辑:
push ebp<sp> [*bp@main] [return@main] [*buffer] [*"SGV....] |*****
mov ebp, esp
<sp><bp> [*bp@main] [return@main] [*buffer] [*"SGV....] |*****push ebx
<sp> [bx@main] <bp> [*bp@main] [return@main] [*buffer] [*"SGV....] |*****lea esp, [esp-(4*2 * 2)]
<sp> [........] [........] [bx@main] <bp> [*bp@main] [return@main] [*buffer] [*"SGV....] |*****==
call __x86_get_pc_thunk_bx
<sp> [return@bd] [........] [........] [bx@main] <bp> [*bp@main] [return@main] [*buffer] [*"SGV....]; eip = *__x86_get_pc_thunk_bx
mov ebx, dword [esp]
; ebx = (long) *<sp>(其实就是拿到位于 .text 段的 ip 指针,也就是
.text+bd+???,GCC 4.9 拿这个 bx (就是当前函数位于的 call __x86_get_pc_thunk_bx 时的 eip)指针去算 .rodata 段的静态只读数据地址)(我们要重新用汇编重写的时候必须也重写这种 ebx 偏移量,把对它们的使用替换成 .rodata 段实际的偏移地址,NASM 可以帮我们做这件事,直接
section .rodata 然后定义 byte/dword 静态数据指针就可以了)ret
<sp> [........] [........] [bx@main] <bp> [*bp@main] [return@main] [*buffer] [*"SGV....]; eip = *bd
; eax = *bd+5i
== 然后我们又回到了自己的程序
add ebx, 0x23fb
; 现在 ebx 指向了 .rodata (ds)段的某个地址,不过,本函数是不用; GCC(GNU Compiler Collection) 4.9 是相当老的编译器了,不要忘记现在 GCC 都出 8 了
mov eax, bd_arg2 (ebp+0xc)eax = my_arg2
mov bd_suba2(esp+0x4), eax
mov eax, bd_arg1 (ebp+0x8)eax = my_arg1
mov bd_suba1(esp), eax
<sp> [my_arg1|my_arg2] [........] [bx@main] <bp> [*bp@main] [return@main] [*buffer] [*"SGV....]🤔所以,我们为什么要多分配这么多无用的东西?浪费了一个双字的空间(虽然 mov subarg2 的时候可能溢出到别的存储单元)
call BD
; BD(my_arg1, my_arg2)🤔
lea esp, [esp+framesz]
[my_arg1|my_arg2] [........] <sp> [bx@main] <bp> [*bp@main] [return@main] [*buffer] [*"SGV....]一瞬返回
pop ebx
<sp> <bp> [*bp@main] [return@main] [*buffer] [*"SGV....]pop ebp<sp> [return@main] [*buffer] [*"SGV....]
ret一瞬重置代码指针返回 main+???
最后 main 收拾调用现场
== main+???
add esp, (2*4)
<sp> |*****对 bd 的调用就完成了(迫真)
duangsuse::Echo
lea esp, [esp - framesz] 有什么用呢? 🤔
注意:
1. 是
1.6. 我们要分配 4 个本地变量(4 * 4),当然也和我们自己调用子程序的部分有重叠
2. framesz 是 frame size 的意思,有时候你们看到的 sz 表示的 handle 们只是『碰巧』使用 size_t 机器字大小存储而已,所以叫 size,和这个无关
3. 我也不知道为什么 X86 的寄存器就会有 64 位了,因为这个是反汇编出来的程序又是 -m32 multlib 编译肯定有点奇怪啊
4. 我的机器很高级,支持 Debug Registers、FPU 还有 MMX、SSE、AVX 这些 SIMD 处理特性,可以快快的解码视频(迫真
6. 上面那些高等 Vectorize 处理特性,我们要分析的程序都不会用到(悲)
7. 这条指令执行前,esp 指向 0xb4f8,执行后,esp 指向 0xb4e4,下移了 20 个字节(合 5 个字)
8. 这啥 🐔 玩意,我也不知道它要干什么
9. 好吧,告诉你们,就是下移了 4 个字(4 * 4)而已,所谓 20 字节是我瞎 🐔 猜的
10. 所以现在看得懂汇编了吗?
1. 是
lea esp, [esp-framesz] 不是 mov esp, [esp-framesz]
1.5. 0x10 是 16 的意思,16 / 4 等于 41.6. 我们要分配 4 个本地变量(4 * 4),当然也和我们自己调用子程序的部分有重叠
2. framesz 是 frame size 的意思,有时候你们看到的 sz 表示的 handle 们只是『碰巧』使用 size_t 机器字大小存储而已,所以叫 size,和这个无关
3. 我也不知道为什么 X86 的寄存器就会有 64 位了,因为这个是反汇编出来的程序又是 -m32 multlib 编译肯定有点奇怪啊
4. 我的机器很高级,支持 Debug Registers、FPU 还有 MMX、SSE、AVX 这些 SIMD 处理特性,可以快快的解码视频(迫真
6. 上面那些高等 Vectorize 处理特性,我们要分析的程序都不会用到(悲)
7. 这条指令执行前,esp 指向 0xb4f8,执行后,esp 指向 0xb4e4,下移了 20 个字节(合 5 个字)
8. 这啥 🐔 玩意,我也不知道它要干什么
9. 好吧,告诉你们,就是下移了 4 个字(4 * 4)而已,所谓 20 字节是我瞎 🐔 猜的
10. 所以现在看得懂汇编了吗?
duangsuse::Echo
执行时是怎么样的呢? 🤔(当然这里可能不严谨,不过也够了,反正大家很多人连 CDEF 系统栈是怎么维护的都不知道,也算是科普一下) 我们的 caller 叫做 main,它执行如下代码以调用我们的子程序 bd: sub esp, (2*4) <sp> [....] [....] |***** mov ecx, ; buffer ; ecx = (char *) buffer mov [esp+4], "SGVsbG8K" <sp> [....] [*"SGV....] |***** mov [esp]…
🤔 实际上还是得重写 liba.so 真正自己的逻辑,不能直接反汇编然后啥都 OK 了...
duangsuse::Echo
lea esp, [esp - framesz] 有什么用呢? 🤔
This media is not supported in your browser
VIEW IN TELEGRAM
duangsuse::Echo
🐶 Sticker
(恍然大雾)我居然忘记给 NASM 加正确的 flag 了!
我没告诉 NASM,我是要给 i386 汇编!
难怪会出现机器字大小不兼容,frame 分配冲突错误(大寄存器 vs 小 frame local variable allocation = read/write 读取或覆盖无关变量)的问题
也就是说... 为什么 e** 寄存器都有 64 位?是因为我的机器是 x86_64 的,而且它自己的机器寄存器大小就有 128 位... 🙁
rax 是一个 qword,那 eax 自然有一个 dword... 🙊
真的是太 *** 了....
我没告诉 NASM,我是要给 i386 汇编!
难怪会出现机器字大小不兼容,frame 分配冲突错误(大寄存器 vs 小 frame local variable allocation = read/write 读取或覆盖无关变量)的问题
也就是说... 为什么 e** 寄存器都有 64 位?是因为我的机器是 x86_64 的,而且它自己的机器寄存器大小就有 128 位... 🙁
rax 是一个 qword,那 eax 自然有一个 dword... 🙊
真的是太 *** 了....
duangsuse::Echo
🤔 实际上还是得重写 liba.so 真正自己的逻辑,不能直接反汇编然后啥都 OK 了...
事实上:本来应该可以的,但是因为我根本没考虑过 *** 的问题,所以居然还有问题!
🤔 觉得调试符号里会保存关于本地变量偏移的信息,正在迫真查找...