如何简化函数“调用自身的引用”

逆向工程 艾达 拆卸 部件 C 静态分析
2021-06-15 11:11:11

我经常遇到一个调用自身的函数(在伪代码中),例如:

result = (**(__int64 (__fastcall ***)(volatile signed __int32 *))lambda)(lambda);
  1. 既然是反汇编call qword ptr [rax]result = lambda();那我把c中的伪代码翻译这样不就可以简化了吗?
  2. 为什么在伪代码中函数将自身作为参数?
  3. 当有电话时会发生什么lambda + 8i64

这里有一个更完整的上下文:

__int64 __fastcall CR_maybeParseWithLambda(_QWORD *a1, __int64 newPtr, __int64 positionOrCounter)
{
  volatile signed __int32 *lambda; // rdi
  __int64 result; // rax

  lambda = (volatile signed __int32 *)a1[1];
  if ( lambda )
  {
    result = (unsigned int)_InterlockedExchangeAdd(lambda + 2, 0xFFFFFFFF);
    if ( (_DWORD)result == 1 )
    {
      result = (**(__int64 (__fastcall ***)(volatile signed __int32 *))lambda)(lambda);
      if ( _InterlockedExchangeAdd(lambda + 3, 0xFFFFFFFF) == 1 )
        result = (*(__int64 (__fastcall **)(volatile signed __int32 *))(*(_QWORD *)lambda + 8i64))(lambda);
      a1[1] = positionOrCounter;
      *a1 = newPtr;
    }
    else
    {
      a1[1] = positionOrCounter;
      *a1 = newPtr;
    }
  }
  else
  {
    a1[1] = positionOrCounter;
    *a1 = newPtr;
  }
  return result;
}

拆解:

.text:0000000180005F70 ; __int64 __fastcall CR_maybeParseWithLambda(_QWORD *a1, __int64 newPtr, __int64 positionOrCounter)
.text:0000000180005F70 CR_maybeParseWithLambda proc near       ; CODE XREF: sub_180005B10+10F↑p
.text:0000000180005F70                                         ; sub_180005B10+14A↑p ...
.text:0000000180005F70
.text:0000000180005F70 arg_0           = qword ptr  8
.text:0000000180005F70 arg_8           = qword ptr  10h
.text:0000000180005F70 arg_10          = qword ptr  18h
.text:0000000180005F70 arg_18          = qword ptr  20h
.text:0000000180005F70
.text:0000000180005F70                 mov     [rsp+arg_8], rbx
.text:0000000180005F75                 mov     [rsp+arg_10], rbp
.text:0000000180005F7A                 mov     [rsp+arg_18], rsi
.text:0000000180005F7F                 push    rdi
.text:0000000180005F80                 sub     rsp, 20h
.text:0000000180005F84                 mov     rdi, [rcx+8]
.text:0000000180005F88                 mov     rsi, r8
.text:0000000180005F8B                 mov     rbp, rdx
.text:0000000180005F8E                 mov     rbx, rcx
.text:0000000180005F91                 test    rdi, rdi
.text:0000000180005F94                 jz      short loc_180005FF3
.text:0000000180005F96
.text:0000000180005F96 loc_180005F96:                          ; DATA XREF: .rdata:0000000180401E74↓o
.text:0000000180005F96                                         ; .rdata:0000000180401E84↓o ...
.text:0000000180005F96                 mov     [rsp+28h+arg_0], r14
.text:0000000180005F9B                 or      r14d, 0FFFFFFFFh
.text:0000000180005F9F                 mov     eax, r14d
.text:0000000180005FA2                 lock xadd [rdi+8], eax
.text:0000000180005FA7                 cmp     eax, 1
.text:0000000180005FAA                 jnz     short loc_180005FEA
.text:0000000180005FAC                 mov     rax, [rdi]
.text:0000000180005FAF                 mov     rcx, rdi
.text:0000000180005FB2                 call    qword ptr [rax]
.text:0000000180005FB4                 lock xadd [rdi+0Ch], r14d
.text:0000000180005FBA                 cmp     r14d, 1
.text:0000000180005FBE                 jnz     short loc_180005FC9
.text:0000000180005FC0                 mov     rax, [rdi]
.text:0000000180005FC3                 mov     rcx, rdi
.text:0000000180005FC6                 call    qword ptr [rax+8]
.text:0000000180005FC9
.text:0000000180005FC9 loc_180005FC9:                          ; CODE XREF: CR_maybeParseWithLambda+4E↑j
.text:0000000180005FC9                 mov     [rbx+8], rsi
.text:0000000180005FCD                 mov     [rbx], rbp
.text:0000000180005FD0
.text:0000000180005FD0 loc_180005FD0:                          ; CODE XREF: CR_maybeParseWithLambda+81↓j
.text:0000000180005FD0                 mov     r14, [rsp+28h+arg_0]
.text:0000000180005FD5
.text:0000000180005FD5 loc_180005FD5:                          ; CODE XREF: CR_maybeParseWithLambda+8A↓j
.text:0000000180005FD5                                         ; DATA XREF: .pdata:0000000180483888↓o ...
.text:0000000180005FD5                 mov     rbx, [rsp+28h+arg_8]
.text:0000000180005FDA                 mov     rbp, [rsp+28h+arg_10]
.text:0000000180005FDF                 mov     rsi, [rsp+28h+arg_18]
.text:0000000180005FE4                 add     rsp, 20h
.text:0000000180005FE8                 pop     rdi
.text:0000000180005FE9                 retn
1个回答

它不是在调用自己;您忽略*了调用表达式开头取消引用。如:

result = (**(__int64 (__fastcall ***)(volatile signed __int32 *))lambda)(lambda);

注意到**第一个括号内的两个了吗?它正在取消引用名为 的变量中保存的地址lambda,程序集明确指出:

.text:0000000180005FAC    mov     rax, [rdi]      ; dereference #1
.text:0000000180005FAF    mov     rcx, rdi
.text:0000000180005FB2    call    qword ptr [rax] ; dereference #2

这是对虚函数的调用。#1从对象中加载 VTable 指针;#2将函数指针 at 调用+0到 VTable 中。

通常,在为lambda和 VTable创建第二个类型之前,在反编译中这总是看起来很糟糕一旦你这样做了,它会向你展示一些很像这样的东西(取自我的 ComRAT IDB):

if ( v9 )
{
  if ( !_InterlockedDecrement(&v9->_Uses) )
  {
    v9->_Destroy(v9);
    if ( !_InterlockedDecrement(&v9->_Weaks) )
      v9->_Delete_this(v9);
  }
}