重定向/重新映射/重新路由内存访问

逆向工程 艾达 拆卸 部件 记忆
2021-07-06 20:04:03

我需要你们的帮助!目前,我正在开发一个 IDA Pro 数据库,以便为可执行文件创建补丁,我完全坚持编辑以下子:

.text:008EC420 ; char __thiscall sub_8EC420(MyClass *this)
.text:008EC420 sub_8EC420      proc near
.text:008EC420 var_8           = dword ptr -8
.text:008EC420 var_4           = dword ptr -4
.text:008EC420                 sub     esp, 8
.text:008EC423                 push    ebx
.text:008EC424                 mov     ebx, ecx
.text:008EC426                 cmp     dword ptr [ebx+79954h], 0
.text:008EC42D                 mov     [esp+0Ch+var_4], ebx
.text:008EC431                 mov     [esp+0Ch+var_8], 0
.text:008EC439                 jle     loc_8EC4F2
.text:008EC43F                 push    ebp
.text:008EC440                 push    esi
.text:008EC441                 push    edi
.text:008EC442                 lea     edi, [ebx+114h]
.text:008EC448                 jmp     short loc_8EC450
.text:008EC44A                 align 10h
.text:008EC450 loc_8EC450:
.text:008EC450                 lea     eax, [edi-0Ch]
.text:008EC453                 push    eax
.text:008EC454                 call    sub_A00890
.text:008EC459                 mov     esi, eax
.text:008EC45B                 add     esp, 4
.text:008EC45E                 cmp     esi, 0FFFFFFFFh
.text:008EC461                 jnz     short loc_8EC472
.text:008EC463                 mov     dword ptr [edi], 0
.text:008EC469                 mov     dword ptr [edi-4], 0FFFFh
.text:008EC470                 jmp     short loc_8EC480
.text:008EC472 loc_8EC472:
.text:008EC472                 push    esi
.text:008EC473                 call    sub_A00870
.text:008EC478                 add     esp, 4
.text:008EC47B                 mov     [edi], eax
.text:008EC47D                 mov     [edi-4], esi
.text:008EC480 loc_8EC480:
.text:008EC480                 xor     ebp, ebp
.text:008EC482                 cmp     [edi+0ECh], ebp
.text:008EC488                 jbe     short loc_8EC4D2
.text:008EC48A                 lea     esi, [edi+0BCh]
.text:008EC490 loc_8EC490:
.text:008EC490                 lea     ecx, [esi-0Ch]
.text:008EC493                 push    ecx
.text:008EC494                 call    sub_A00890
.text:008EC499                 mov     ebx, eax
.text:008EC49B                 add     esp, 4
.text:008EC49E                 cmp     ebx, 0FFFFFFFFh
.text:008EC4A1                 jnz     short loc_8EC4B2
.text:008EC4A3                 mov     dword ptr [esi], 0
.text:008EC4A9                 mov     dword ptr [esi-4], 0FFFFh
.text:008EC4B0                 jmp     short loc_8EC4C0
.text:008EC4B2 loc_8EC4B2:
.text:008EC4B2                 push    ebx
.text:008EC4B3                 call    sub_A00870
.text:008EC4B8                 add     esp, 4
.text:008EC4BB                 mov     [esi], eax
.text:008EC4BD                 mov     [esi-4], ebx
.text:008EC4C0 loc_8EC4C0:
.text:008EC4C0                 add     ebp, 1
.text:008EC4C3                 add     esi, 14h
.text:008EC4C6                 cmp     ebp, [edi+0ECh]
.text:008EC4CC                 jb      short loc_8EC490
.text:008EC4CE                 mov     ebx, [esp+18h+var_4]
.text:008EC4D2 loc_8EC4D2:
.text:008EC4D2                 mov     eax, [esp+18h+var_8]
.text:008EC4D6                 add     eax, 1
.text:008EC4D9                 add     edi, 3E4h
.text:008EC4DF                 cmp     eax, [ebx+79954h]
.text:008EC4E5                 mov     [esp+18h+var_8], eax
.text:008EC4E9                 jl      loc_8EC450
.text:008EC4EF                 pop     edi
.text:008EC4F0                 pop     esi
.text:008EC4F1                 pop     ebp
.text:008EC4F2 loc_8EC4F2:
.text:008EC4F2                 mov     al, 1
.text:008EC4F4                 pop     ebx
.text:008EC4F5                 add     esp, 8
.text:008EC4F8                 retn
.text:008EC4F8 sub_8EC420      endp

MyClass实体如下所示:

struct MyClass // 502076 bytes
{
  void *VFT; // 4 bytes
  MyStruct Structs[500]; // 498000 bytes = sizeof(MyStruct)=996 * 500
  // more data...
};

为了允许MyClass解析和管理更多的MyStruct实例,我扩大.data了可执行文件部分,sizeof(MyStruct1)=996 * 1000 = 996000 bytesMyStruct[1000]在它的末尾附加了一个新的。现在,我需要做的就是将每个试图访问MyClass.Structs内存区域的内存指针移动MyStruct[1000]内存区域。许多修改很容易实现,但我真的不知道如何处理这个。

该方法sub_8EC420遍历每个MyStruct实例以MyClass.Structs获取特定字段并对其进行一些操作:

char *v2 = &this->Structs[0].ValueAt272;
// offset = MyClass + 276 | MyClass->Structs + 272

do
{
    // operations...
    v2 += 996; // sizeof(MyStruct)
}
while ( ... );

为了成功地将内存指针重定向到MyStruct[1000]位于.data末尾的新数组,我必须更改以下指令:

.text:008EC442                 lea     edi, [ebx+114h]
// offset = MyClass + 276 | MyClass->Structs + 272
// bytes = 8D BB 14 01 00 00

EBX是指向我的MyClass实例偏移量的寄存器但我不能把它变成这样:

.text:008EC442                 mov edi, 2DABF84h; nop;

因为,正如您所看到的,紧接着,EDI寄存器值正在被使用,这将导致糟糕的结果:

.text:008EC450                 lea     eax, [edi-0Ch]

我也尝试了一种经过编辑的LEA方法,但也没有产生好的结果:

.text:008EC442                 lea     edi, [ebx+14A027Ch]
// offset = MyStruct[1000] (0x02DABE74) - MyClass Instance (0x190BD08) + 272
// bytes = 8D BB 7C 02 4A 01

最重要的是,向这个子节点插入额外的字节完全破坏了我的 IDA Pro 数据库。那么……我该怎么处理呢?

2个回答

修补指令的一种方法lea eax, [edi-0Ch]是在代码内部创建一个高级绕行到您自己的自定义 .text 段,然后再次返回到代码。

对于常规mov reg32, imm32操作码,您至少需要 5 个字节的空间,这显然永远不会适合 3 字节操作码。

对于绕行操作码序列,您需要制作自己的相对跳转(5 个字节),或者使用最短语法进行绝对跳转(6 个字节):

PatchStart:
    push  loc_patch1  ;; push address of the patch code
    ret               ;; pop address and jump to it

所以如果代码最初是这样的:

.text:008EC44A                 align 10h
.text:008EC450 loc_8EC450:
.text:008EC450                 lea     eax, [edi-0Ch] ;; 3 bytes
.text:008EC453                 push    eax            ;; 1 byte
.text:008EC454                 call    sub_A00890     ;; 5 bytes
.text:008EC459                 

您可以将其替换为:

.text:008EC44A                 align 10h
.text:008EC450 loc_8EC450:
.text:008EC450                 push    loc_patch1     ;; 5 bytes
.text:008EC455                 ret                    ;; 1 byte
.text:008EC456                 nop                    ;; pad other 3 bytes
.text:008EC457                 nop  
.text:008EC458                 nop
.text:008EC459                 

现在对于补丁本身:

           loc_patch1:
                           mov     eax, PatchedValue ;; lea eax,[edi-0Ch]
                           push    eax            
                           call    sub_A00890     
                           push    loc_8EC459     ;; jump back to source
                           ret

长绝对跳转会导致一些性能损失,但最终它会修补您的可执行文件,而无需进行任何繁琐的重定位。

如果您想制作自己的长相对跳转/调用,则操作码(5 个字节)如下所示:

;; call +0xCAFE
E8 FE CA 00 00
;; jmp  +0xCAFE
E9 FE CA 00 00

好处是相对跳转只需要 5 个字节。因此,如果您创建一个新的第二个文本段或替换原始 .text 段中的一些未使用的代码,您就可以开始了。

您使用本地无条件 jmp 到另一个内存位置,然后在那里做你想做的事。理想情况下,在函数之前或之后有空间供您将指令放在那里。否则,您正在考虑重新定位整个函数(有点像重新分配,仅在 .text 部分,如果需要,您可以整体变大),然后 long jmp 到您的代码,然后 long jmp 返回。不要忘记让这些跳跃相对于长距离跳跃,这样各种形式的 ASLR 就不会影响你。

如果您必须内联执行它,那么您只能通过足够的字节来优化代码。请记住保持相对跳跃的位置相同。