Radare 产生一堆`add byte [rax], al`,但为什么呢?

逆向工程 拆卸 雷达2 反汇编者
2021-07-05 06:30:40

一堆add byte [rax], al是什么意思?我看到很多内存寻址指向共享库 (.dll) 的特定部分,例如,这...

  0x10064faf8      0000           add byte [rax], al
  0x10064fafa      0000           add byte [rax], al
  0x10064fafc      0000           add byte [rax], al
  0x10064fafe      0000           add byte [rax], al
     ; XREFS: DATA 0x10041db20  DATA 0x100545d2c  DATA 0x100546999  DATA 0x1005469b0  DATA 0x100549de0  DATA 0x100549e00  
  0x10064fb00      0000           add byte [rax], al
  0x10064fb02      0000           add byte [rax], al
  0x10064fb04      0000           add byte [rax], al
  0x10064fb06      0000           add byte [rax], al

当我看到它时,它应该向我表明什么?当 dll 加载到内存中时,这些空间会被重写吗?

3个回答

我在这里添加另一个答案,因为 op 的评论类似于一个新问题

我还是很困惑。如果 ix 对我 >!seek 的点也有很多引用,为什么没有数据和代码?为什么 >! 这些引用会指向填充区域或对齐区域?

这是一个被引用的代码演示,但在引用上执行 pd 会产生一堆零,并且与对齐或任何其他工件无关

C:\evancarr>cat evancarr0.cpp
#include <stdio.h>
#include <windows.h>
char somecipher[MAX_PATH + 1];
char curdir[MAX_PATH + 1];
char deccipher[MAX_PATH + 1];
int main(void) {
    GetCurrentDirectoryA(MAX_PATH, curdir);
    int cdlen = strlen(curdir);
    for (int i = 0; i < cdlen; i++) {
        somecipher[i] = curdir[i] ^ 0x1;
    }
    printf("%s\n", somecipher);
    for (int i = 0; i < cdlen; i++) {
        deccipher[i] = somecipher[i] ^ 0x1;
    }
    printf("%s\n", deccipher);
}

编译并执行

C:\evancarr>cl /Zi /W4 /analyze /EHsc /O2 evancarr0.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 19.12.25835 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

evancarr0.cpp
Microsoft (R) Incremental Linker Version 14.12.25835.0
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:evancarr0.exe
/debug
evancarr0.obj

C:\evancarr>evancarr0.exe
B;]dw`ob`ss
C:\evancarr

将它加载到radare2 中,寻求main 并在引用的全局缓冲区上做一个pd(可以看出缓冲区有很多外部参照,但它是一堆零,反汇编会抛出一堆 add [eax] , al

C:\evancarr>radare2 -AA evancarr0.exe

[0x004015cd]> s 0x4065a0

[0x004065a0]> pd 5
|              ; JMP XREF from 0x00403161 (sub.KERNEL32.dll_GetCurrentDirectoryA_161)
|           0x004065a0      56             push esi
|           0x004065a1      68380d4600     push 0x460d38 <<<<<<<
|           0x004065a6      6804010000     push 0x104                  ; 260
|           0x004065ab      ff1500304600   call dword [sym.imp.KERNEL32.dll_GetCurrentDirectoryA] ;
0x463000
|           0x004065b1      be380d4600     mov esi, 0x460d38


[0x004065a0]> pd 5 @ 0x460d38 
               ; DATA XREF from 0x004065a1  
               ; DATA XREF from 0x004065b1 
               ; DATA XREF from 0x004065f1 
               ; DATA XREF from 0x00406650 
               ; DATA XREF from 0x004065c0 

            0x00460d38      0000           add byte [eax], al
            0x00460d3a      0000           add byte [eax], al
            0x00460d3c      0000           add byte [eax], al
            0x00460d3e      0000           add byte [eax], al
            0x00460d40      0000           add byte [eax], al


[0x004065a0]> pd 5 @ 0x460c30
               ; DATA XREF from 0x00406658 
               ; DATA XREF from 0x00406663 
               ; DATA XREF from 0x004066a0 
               ; DATA XREF from 0x00406700 
               ; DATA XREF from 0x004065fc 


            0x00460c30      0000           add byte [eax], al
            0x00460c32      0000           add byte [eax], al
            0x00460c34      0000           add byte [eax], al
            0x00460c36      0000           add byte [eax], al
            0x00460c38      0000           add byte [eax], al
[0x004065a0]>
add byte [eax], al 

这条指令是由不区分存储的缓冲区/空跨度和代码段的反汇编程序错误地和意外地盲目翻译的,要解释这里发生的事情,您可以参考此博客部分

ADD有一个操作码等于0000(h)=00000000 0000 0000(2)其中命令操作码的最后两个标志位 {d,s} 未设置,表示从寄存器到 R/M 字段的添加,s代表传输大小为 8 位 = 2 字节。

第二个操作数表示将 reg 值添加到 EAX 中的本地地址,在 32 位英特尔 ASM 中,它是00(h)为 reg编码AL,我不知道 86/64x 架构,但我想它是一样的。所以你看,纯属巧合。

空跨度也是一种情况,其中程序保留额外空间来存储导入的 DLL 函数的入口点,用于本地调用的标签、本地常量/字符串或任何形式的分散数据块之间。

这些类型的 0' 跨度在每次执行实例后以不同方式在 RAM 中转储自身的多态程序经常被标记,在这些程序中,它们经常以针对解包程序和任何形式的代码跟踪的规避方式更改其相对 EP 和函数调用地址。

一个非常强烈的猜测,填充数据的这种流或储存用于高速缓存目的或steganographed应该由前面JMP的指令CALLRET,否则,必须有一个问题。

请参阅此处的一些调试器/反编译器的示例,这些调试器/反编译器识别填充的 DB 并跳过它们。

在此处输入图片说明

您可能在没有数据或编码的区域中的任何已知功能之外进行了查找,该区域是一个填充区域以满足页面/部分大小的对齐要求

也称为零填充区域

例如

[0x010546bc]> px 10 ; pd 10
- offset -   0 1  2 3  4 5  6 7  8 9  A B  C D  E F  0123456789ABCDEF

0x010546bc  0000 0000 0000 0000 0000                 ..........
            0x010546bc      0000           add byte [eax], al
            0x010546be      0000           add byte [eax], al
            0x010546c0      0000           add byte [eax], al
            0x010546c2      0000           add byte [eax], al
            0x010546c4      0000           add byte [eax], al
            0x010546c6      0000           add byte [eax], al
            0x010546c8      0000           add byte [eax], al
            0x010546ca      0000           add byte [eax], al
            0x010546cc      0000           add byte [eax], al
            0x010546ce      0000           add byte [eax], al
[0x010546bc]>