Vector35 / binaryninja-api

Public API, examples, documentation and issues for Binary Ninja
https://binary.ninja/
MIT License
903 stars 203 forks source link

Unnecessary variable assignation in HLIL output #4145

Open op2786 opened 1 year ago

op2786 commented 1 year ago

Version and Platform (required):

Bug Description:

I saw a lot of decompiler output like below. I wonder if this is a bug or a example waiting for optimization. I expect BN to get rid of that automatically.

I can share the binary if needed.

NOTE: Please read this comment, this issue could be related to some spesific binaries that uses __fastcall or __thiscall in 32 bit binaries.

void __fastcall write_to_file(char* lpFileName, void* buffer, uint32_t size)

uint32_t written = lpFileName
written = 0
HANDLE hFile = CreateFileA(lpFileName, 0x40000000, FILE_SHARE_NONE, nullptr, CREATE_ALWAYS, SECURITY_ANONYMOUS, nullptr)
if (hFile != -1) {
  WriteFile(hFile, buffer, size, &written, nullptr)
  CloseHandle(hFile)
}

Disassembly:

void __fastcall write_to_file(char* lpFileName, void* buffer, uint32_t size)

55                 push    ebp {__saved_ebp}
8bec               mov     ebp, esp {__saved_ebp}
51                 push    ecx {written}
53                 push    ebx {__saved_ebx}  {0x0}
56                 push    esi {__saved_esi}
57                 push    edi {__saved_edi}
33db               xor     ebx, ebx  {0x0}
8bfa               mov     edi, edx
53                 push    ebx {var_18}  {0x0}
53                 push    ebx {var_1c}  {0x0}
6a02               push    0x2 {var_20}
53                 push    ebx {var_24}  {0x0}
53                 push    ebx {var_28}  {0x0}
6800000040         push    0x40000000 {var_2c}
51                 push    ecx {var_30}
895dfc             mov     dword [ebp-0x4 {written}], ebx  {0x0}
ff1518914100       call    dword [CreateFileA]
8bf0               mov     esi, eax
83feff             cmp     esi, 0xffffffff
7417               je      0x415cbf

53                 push    ebx {var_18}  {0x0}
8d45fc             lea     eax, [ebp-0x4 {written}]
50                 push    eax {written} {var_1c_1}
ff7508             push    dword [ebp+0x8 {size}] {var_20_1}
57                 push    edi {var_24_1}
56                 push    esi {var_28_1}
ff15ec904100       call    dword [WriteFile]
56                 push    esi {var_18_1}
ff15fc914100       call    dword [CloseHandle]

5f                 pop     edi {__saved_edi}
5e                 pop     esi {__saved_esi}
5b                 pop     ebx {__saved_ebx}  {0x0}
c9                 leave    {__saved_ebp}
c3                 retn     {__return_addr}

Another example:

uint32_t lpNumberOfBytesRead = lpFileName
void* buffer = my_alloc(0x2800000)
lpNumberOfBytesRead = 0
HANDLE hFile = CreateFileA(lpFileName, 0x80000000, FILE_SHARE_NONE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr)
if (hFile == 0xffffffff) {
  *size_out = 0
}

Disassembly:

55                 push    ebp {__saved_ebp}
8bec               mov     ebp, esp {__saved_ebp}
51                 push    ecx {lpNumberOfBytesRead}
53                 push    ebx {__saved_ebx}  {0x0}
56                 push    esi {__saved_esi}
57                 push    edi {__saved_edi}
6800008002         push    0x2800000
8bfa               mov     edi, edx
8bf1               mov     esi, ecx
e8c4b1feff         call    my_alloc
59                 pop     ecx  {0x2800000}
8bd8               mov     ebx, eax
33c0               xor     eax, eax  {0x0}
50                 push    eax  {0x0}
6880000000         push    0x80
6a03               push    0x3
50                 push    eax  {0x0}
50                 push    eax  {0x0}
6800000080         push    0x80000000 {var_2c}  {0x80000000}
56                 push    esi {var_30}
8945fc             mov     dword [ebp-0x4 {lpNumberOfBytesRead}], eax  {0x0}
ff1518914100       call    dword [CreateFileA]
8bf0               mov     esi, eax
83feff             cmp     esi, 0xffffffff
7503               jne     0x415e64
op2786 commented 1 year ago

I believe the example below could have same root cause as this issue:

int32_t main(int32_t argc, char** argv, char** envp) __noreturn

08048d13  char buf[0x108]
08048d13  buf[0x104].d = &argc
08048d22  puts("welcome to the land of sunshine …")
08048d06  8d4c2404           lea     ecx, [esp+0x4 {argc}]
08048d0a  83e4f0             and     esp, 0xfffffff0
08048d0d  ff71fc             push    dword [ecx-0x4 {__return_addr}] {var_4}
08048d10  55                 push    ebp {var_8}
08048d11  89e5               mov     ebp, esp {var_8}
08048d13  51                 push    ecx {argc} {buf[0x104].d}
08048d14  81ec04010000       sub     esp, 0x104
08048d1a  83ec0c             sub     esp, 0xc
08048d1d  68cc630508         push    data_80563cc  {"welcome to the land of sunshine …"}
08048d22  e839fdffff         call    puts
op2786 commented 1 year ago

And this could be related too, which corrupts decompiler output a lot in my opinion. At 004141a9 it does not uses directly i for increment and try to do it using module somehow. 004141e3 and 00414208 are also interesting. I can share the binaries and BNDBs for these examples in slack.

void __thiscall pe_copy_sections(struct struct_pe* stpe, struct DOS_Header* module)

00414124  struct DOS_Header* DosHdr = module
0041412e  stpe->DosHdr = DosHdr
00414134  if (DosHdr->e_magic == 0x5a4d) {
0041413d    struct COFF_Header* NtHdrs = &DosHdr->e_magic[DosHdr->e_lfanew]
00414145    if (NtHdrs->magic == 0x4550) {
0041414b      enum coff_machine machine = NtHdrs->machine
00414157      int32_t sdata
00414157      if (machine == IMAGE_FILE_MACHINE_I386) {
00414159        stpe->is_32 = 1
00414163        stpe->NtHdr = NtHdrs
0041416a        init_buffer(&stpe->headers, DosHdr, NtHdrs->OptionalHeader.sizeOfHeaders)
0041416f        NtHdrs = stpe->NtHdr
00414172        module = nullptr
0041417d        struct Section_Header* pSection = &NtHdrs->OptionalHeader + zx.d(NtHdrs->sizeOfOptionalHeader)
00414185        if (0 u< NtHdrs->numberOfSections) {
004141b3          int32_t i
004141b3          do {
00414193            pe_get_section_data(&sdata, DosHdr, pSection, &sdata)
0041419b            pe_append_to_section_list(&stpe->section_list, sdata)
004141a3            pSection = &pSection[1]
004141a9            i = &module->e_magic[1]
004141aa            module = i
004141aa          } while (i s< zx.d(stpe->NtHdr->numberOfSections))
004141a0        }
00414181      } else if (machine == IMAGE_FILE_MACHINE_AMD64) {
004141c1        int32_t ebx_2 = 0
004141c3        stpe->NtHdr64 = NtHdrs
004141c6        stpe->is_32 = 0
004141d0        init_buffer(&stpe->headers, DosHdr, NtHdrs->OptionalHeader.sizeOfHeaders)
004141d5        struct COFF_Header* ecx_5 = stpe->NtHdr64
004141e1        struct Section_Header* eax_7 = zx.d(ecx_5->sizeOfOptionalHeader) + 0x18 + ecx_5
004141e3        module = eax_7
004141ea        if (0 u< ecx_5->numberOfSections) {
00414214          do {
004141f4            pe_get_section_data(&sdata, DosHdr, eax_7, &sdata)
004141fc            pe_append_to_section_list(&stpe->section_list, sdata)
00414204            ebx_2 = ebx_2 + 1
00414208            eax_7 = &module->e_res2
0041420b            module = eax_7
0041420b          } while (ebx_2 s< zx.d(stpe->NtHdr64->numberOfSections))
00414201        }
004141e6      }
00414219      stpe->field_3c = 1
00414219    }
0041413f  }

Disassembly:

void __thiscall pe_copy_sections(struct struct_pe* stpe, struct DOS_Header* module)

0041411e  55                 push    ebp {__saved_ebp}
0041411f  8bec               mov     ebp, esp {__saved_ebp}
00414121  53                 push    ebx {__saved_ebx}  {0x0}
00414122  56                 push    esi {__saved_esi}
00414123  57                 push    edi {__saved_edi}
00414124  8b7d08             mov     edi, dword [ebp+0x8 {module}]
00414127  8bf1               mov     esi, ecx
00414129  b84d5a0000         mov     eax, 0x5a4d
0041412e  897e20             mov     dword [esi+0x20 {struct_pe::DosHdr}], edi
00414131  663907             cmp     word [edi {DOS_Header::e_magic}], ax
00414134  0f85e4000000       jne     0x41421e

0041413a  8b473c             mov     eax, dword [edi+0x3c {DOS_Header::e_lfanew}]
0041413d  03c7               add     eax, edi
0041413f  813850450000       cmp     dword [eax {COFF_Header::magic}], 0x4550
00414145  0f85d3000000       jne     0x41421e

0041414b  0fb74804           movzx   ecx, word [eax+0x4 {COFF_Header::machine}]
0041414f  ba4c010000         mov     edx, 0x14c
00414154  663bca             cmp     cx, dx
00414157  755e               jne     0x4141b7

00414159  c7464001000000     mov     dword [esi+0x40 {struct_pe::is_32}], 0x1
00414160  8d4e18             lea     ecx, [esi+0x18] {struct_pe::headers}
00414163  894624             mov     dword [esi+0x24 {struct_pe::NtHdr}], eax
00414166  ff7054             push    dword [eax+0x54 {COFF_Header::OptionalHeader.sizeOfHeaders}] {var_14_1}
00414169  57                 push    edi {var_18_1}
0041416a  e858fefeff         call    init_buffer
0041416f  8b4e24             mov     ecx, dword [esi+0x24 {struct_pe::NtHdr}]
00414172  83650800           and     dword [ebp+0x8 {module}], 0x0
00414176  0fb74114           movzx   eax, word [ecx+0x14 {COFF_Header::sizeOfOptionalHeader}]
0041417a  8d5918             lea     ebx, [ecx+0x18] {COFF_Header::OptionalHeader}
0041417d  03d8               add     ebx, eax
0041417f  33c0               xor     eax, eax  {0x0}
00414181  663b4106           cmp     ax, word [ecx+0x6 {COFF_Header::numberOfSections}]
00414185  0f838b000000       jae     0x414216

0041418b  83ec30             sub     esp, 0x30
0041418e  8bcc               mov     ecx, esp {sdata}
00414190  51                 push    ecx {sdata} {var_44_1}
00414191  53                 push    ebx {var_48_1}
00414192  57                 push    edi {var_4c_1}
00414193  e8fc060000         call    pe_get_section_data
00414198  8d4e2c             lea     ecx, [esi+0x2c] {struct_pe::section_list}
0041419b  e8dbe9feff         call    pe_append_to_section_list
004141a0  8b4624             mov     eax, dword [esi+0x24 {struct_pe::NtHdr}]
🐛004141a3  83c328             add     ebx, 40
004141a6  8b4d08             mov     ecx, dword [ebp+0x8 {module}]
004141a9  41                 inc     ecx {DOS_Header::e_magic[1]}
004141aa  894d08             mov     dword [ebp+0x8 {module}], ecx
004141ad  0fb74006           movzx   eax, word [eax+0x6 {COFF_Header::numberOfSections}]
004141b1  3bc8               cmp     ecx, eax
004141b3  7cd6               jl      0x41418b

004141b5  eb5f               jmp     0x414216

004141b7  ba64860000         mov     edx, 0x8664
004141bc  663bca             cmp     cx, dx
004141bf  7555               jne     0x414216

004141c1  33db               xor     ebx, ebx  {0x0}
004141c3  894628             mov     dword [esi+0x28 {struct_pe::NtHdr64}], eax
004141c6  895e40             mov     dword [esi+0x40 {struct_pe::is_32}], ebx  {0x0}
004141c9  8d4e18             lea     ecx, [esi+0x18] {struct_pe::headers}
004141cc  ff7054             push    dword [eax+0x54 {COFF_Header::OptionalHeader.sizeOfHeaders}] {var_14_2}
004141cf  57                 push    edi {var_18_2}
004141d0  e8f2fdfeff         call    init_buffer
004141d5  8b4e28             mov     ecx, dword [esi+0x28 {struct_pe::NtHdr64}]
004141d8  33d2               xor     edx, edx  {0x0}
004141da  0fb74114           movzx   eax, word [ecx+0x14 {COFF_Header::sizeOfOptionalHeader}]
004141de  83c018             add     eax, 0x18
004141e1  03c1               add     eax, ecx
004141e3  894508             mov     dword [ebp+0x8 {module}], eax
004141e6  663b5106           cmp     dx, word [ecx+0x6 {COFF_Header::numberOfSections}]
004141ea  732a               jae     0x414216

004141ec  83ec30             sub     esp, 0x30
004141ef  8bcc               mov     ecx, esp {sdata}
004141f1  51                 push    ecx {sdata} {var_44_2}
004141f2  50                 push    eax {var_48_2}
004141f3  57                 push    edi {var_4c_2}
004141f4  e89b060000         call    pe_get_section_data
004141f9  8d4e2c             lea     ecx, [esi+0x2c] {struct_pe::section_list}
004141fc  e87ae9feff         call    pe_append_to_section_list
00414201  8b4e28             mov     ecx, dword [esi+0x28 {struct_pe::NtHdr64}]
00414204  43                 inc     ebx
00414205  8b4508             mov     eax, dword [ebp+0x8 {module}]
00414208  83c028             add     eax, 0x28 {DOS_Header::e_res2}
0041420b  894508             mov     dword [ebp+0x8 {module}], eax
0041420e  0fb74906           movzx   ecx, word [ecx+0x6 {COFF_Header::numberOfSections}]
00414212  3bd9               cmp     ebx, ecx
00414214  7cd6               jl      0x4141ec

00414216  33c0               xor     eax, eax
00414218  40                 inc     eax  {0x1}
00414219  89463c             mov     dword [esi+0x3c {struct_pe::field_3c}], eax  {0x1}
0041421c  eb02               jmp     0x414220

0041421e  33c0               xor     eax, eax  {0x0}

00414220  5f                 pop     edi {__saved_edi}
00414221  5e                 pop     esi {__saved_esi}
00414222  5b                 pop     ebx {__saved_ebx}  {0x0}
00414223  5d                 pop     ebp {__saved_ebp}
00414224  c20400             retn    0x4 {__return_addr}
op2786 commented 1 year ago

Another example from same binary:

int32_t __thiscall reverse_proxy_thread__(struct proxy_ctx* ctx, struct proxy_thread_ctx* thread_ctx)

00410ad8  struct proxy_socket_ctx sockets
00410ad8  sockets.remote_socket = ctx
00410ad9  sockets.local_socket = ctx
00410ae6  char* ecx = EnterCriticalSection(&ctx->lock)
00410af3  char* domain_temp
00410af3  int32_t eax_3
00410af3  int32_t result
00410af3  if (ctx->remote_wsa.connected == 0) {
int32_t __thiscall reverse_proxy_thread__(struct proxy_ctx* ctx, struct proxy_thread_ctx* thread_ctx)

00410ad5  55                 push    ebp {__saved_ebp}
00410ad6  8bec               mov     ebp, esp {__saved_ebp}
00410ad8  51                 push    ecx {sockets.remote_socket}
00410ad9  51                 push    ecx {sockets.local_socket}
00410ada  53                 push    ebx {__saved_ebx}  {0x0}
00410adb  56                 push    esi {__saved_esi}
00410adc  57                 push    edi {__saved_edi}
00410add  8bf9               mov     edi, ecx
00410adf  8d9fd8030000       lea     ebx, [edi+0x3d8] {proxy_ctx::lock}
00410ae5  53                 push    ebx {var_1c}
00410ae6  ff158c914100       call    dword [EnterCriticalSection]
00410aec  83bfec01000000     cmp     dword [edi+0x1ec {proxy_ctx::remote_wsa.connected}], 0x0
00410af3  7521               jne     0x410b16

This is a 32 bit executable that uses __fastcall or __thiscall in most of its functions. I believe that these issues could be related to that.

plafosse commented 1 year ago

Thanks for the report. This is one of those long tail issues that will never be fully resolved.