binaryninja-api icon indicating copy to clipboard operation
binaryninja-api copied to clipboard

Strange HLIL with a messed up stack and use of undefined variables

Open joelreymont opened this issue 1 year ago • 8 comments

Version and Platform (required):

  • Binary Ninja Version: 4.1.5272-dev, 3a057a87
  • OS: macos
  • OS Version: 14.4
  • CPU Architecture: arm64

Internal binary major dine favor.

IDA Pro

MD5_CTX *__fastcall DjiMd5_Transform(MD5_CTX *ctx_1, MD5_CTX *ctx_2)
{
  unsigned __int64 v2; // t2
  int data[20]; // [xsp+18h] [xbp-58h]
  int j; // [xsp+68h] [xbp-8h]
  unsigned int i; // [xsp+6Ch] [xbp-4h]

  i = 0;
  j = 0;
  while ( i <= 0xF )
  {
    data[i++] = ctx_2->data[j] + (ctx_2->data[j + 1] << 8) + (ctx_2->data[j + 2] << 16) + (ctx_2->data[j + 3] << 24);
    j += 4;
  }
  data[19] = ctx_1->state[0];
  data[18] = ctx_1->state[1];
  data[17] = ctx_1->state[2];
  data[16] = ctx_1->state[3];

But what is arg_0 in the HLIL below and why does it want to refer to __elf_program_headers all of a sudden?

Also, where's the assignment to data[16] and how do I create uint32_t data[20] on the stack here?

I can rename arg_0 to data and type it as int[20] but that doesn't change the assignments to x0_34, etc. at the end and doesn't add the missing one.

0008575c  struct MD5_CTX* DjiMd5_Transform(struct MD5_CTX* ctx_1, struct MD5_CTX* ctx_2)

00085768      int32_t i = 0
0008576c      int32_t j = 0
00085824      while (i u<= 0xf)
000857e4          uint32_t x0_21 = zx.d(ctx_2->data[zx.q(j)]) + (zx.d(ctx_2->data[zx.q(j + 1)]) << 8) + (zx.d(ctx_2->data[zx.q(j + 2)]) << 0x10) + (zx.d(ctx_2->data[zx.q(j + 3)]) << 0x18)
00085800          *(&arg_0 + (zx.q(i) << 2) - &__elf_program_headers[0].physical_address) = x0_21
0008580c          i += 1
00085818          j += 4
00085838      unsigned int x0_34 = ctx_1->state[1]
00085844      unsigned int x0_36 = ctx_1->state[2]
00085850      unsigned int x0_38 = ctx_1->state[3]
000858a4      int32_t var_58
000858a4      int32_t x0_48 = ror.d(((x0_34 & x0_36) | (not.d(x0_34) & x0_38)) + var_58 + ctx_1->state[0] - 0x28955b88, 0x19) + x0_34

joelreymont avatar May 14 '24 12:05 joelreymont

Here's the disassembly

0008575c  struct MD5_CTX* DjiMd5_Transform(struct MD5_CTX* ctx_1, struct MD5_CTX* ctx_2)

0008575c  ffc301d1   sub     sp, sp, #0x70
00085760  e00700f9   str     x0, [sp, #0x8 {var_68}]
00085764  e10300f9   str     x1, [sp {var_70}]
00085768  ff6f00b9   str     wzr, [sp, #0x6c {i}]  {0x0}
0008576c  ff6b00b9   str     wzr, [sp, #0x68 {j}]  {0x0}
00085770  2b000014   b       0x8581c

00085774  e06b40b9   ldr     w0, [sp, #0x68 {j}]
00085778  e10340f9   ldr     x1, [sp {var_70}]
0008577c  2000008b   add     x0, x1, x0
00085780  00004039   ldrb    w0, [x0]
00085784  e203002a   mov     w2, w0
00085788  e06b40b9   ldr     w0, [sp, #0x68 {j}]
0008578c  00040011   add     w0, w0, #0x1
00085790  e003002a   mov     w0, w0
00085794  e10340f9   ldr     x1, [sp {var_70}]
00085798  2000008b   add     x0, x1, x0
0008579c  00004039   ldrb    w0, [x0]
000857a0  005c1853   lsl     w0, w0, #0x8
000857a4  4100000b   add     w1, w2, w0
000857a8  e06b40b9   ldr     w0, [sp, #0x68 {j}]
000857ac  00080011   add     w0, w0, #0x2
000857b0  e003002a   mov     w0, w0
000857b4  e20340f9   ldr     x2, [sp {var_70}]
000857b8  4000008b   add     x0, x2, x0
000857bc  00004039   ldrb    w0, [x0]
000857c0  003c1053   lsl     w0, w0, #0x10
000857c4  2100000b   add     w1, w1, w0
000857c8  e06b40b9   ldr     w0, [sp, #0x68 {j}]
000857cc  000c0011   add     w0, w0, #0x3
000857d0  e003002a   mov     w0, w0
000857d4  e20340f9   ldr     x2, [sp {var_70}]
000857d8  4000008b   add     x0, x2, x0
000857dc  00004039   ldrb    w0, [x0]
000857e0  001c0853   lsl     w0, w0, #0x18
000857e4  2000000b   add     w0, w1, w0
000857e8  e103002a   mov     w1, w0
000857ec  e06f40b9   ldr     w0, [sp, #0x6c {i}]
000857f0  00f47ed3   lsl     x0, x0, #0x2
000857f4  e2c30191   add     x2, sp, #0x70 {data}
000857f8  4000008b   add     x0, x2, x0 {data}
000857fc  000440d1   sub     x0, x0, #0x1, lsl #0xc
00085800  01a80fb9   str     w1, [x0, #0xfa8]
00085804  e06f40b9   ldr     w0, [sp, #0x6c {i}]
00085808  00040011   add     w0, w0, #0x1
0008580c  e06f00b9   str     w0, [sp, #0x6c {i}]
00085810  e06b40b9   ldr     w0, [sp, #0x68 {j}]
00085814  00100011   add     w0, w0, #0x4
00085818  e06b00b9   str     w0, [sp, #0x68 {j}]

0008581c  e06f40b9   ldr     w0, [sp, #0x6c {i}]
00085820  1f3c0071   cmp     w0, #0xf
00085824  89faff54   b.ls    0x85774

00085828  e00740f9   ldr     x0, [sp, #0x8 {var_68}]
0008582c  005040b9   ldr     w0, [x0, #0x50 {MD5_CTX::state[0]}]
00085830  e06700b9   str     w0, [sp, #0x64 {var_c}]
00085834  e00740f9   ldr     x0, [sp, #0x8 {var_68}]
00085838  005440b9   ldr     w0, [x0, #0x54 {MD5_CTX::state[1]}]
0008583c  e06300b9   str     w0, [sp, #0x60 {var_10}]
00085840  e00740f9   ldr     x0, [sp, #0x8 {var_68}]
00085844  005840b9   ldr     w0, [x0, #0x58 {MD5_CTX::state[2]}]
00085848  e05f00b9   str     w0, [sp, #0x5c {var_14}]
0008584c  e00740f9   ldr     x0, [sp, #0x8 {var_68}]
00085850  005c40b9   ldr     w0, [x0, #0x5c {MD5_CTX::state[3]}]
00085854  e05b00b9   str     w0, [sp, #0x58 {var_18}]
00085858  e16340b9   ldr     w1, [sp, #0x60 {var_10}]
0008585c  e05f40b9   ldr     w0, [sp, #0x5c {var_14}]
00085860  2100000a   and     w1, w1, w0
00085864  e06340b9   ldr     w0, [sp, #0x60 {var_10}]
00085868  e203202a   mvn     w2, w0
0008586c  e05b40b9   ldr     w0, [sp, #0x58 {var_18}]
00085870  4000000a   and     w0, w2, w0
00085874  2100002a   orr     w1, w1, w0
00085878  e01b40b9   ldr     w0, [sp, #0x18 {var_58}]
0008587c  2100000b   add     w1, w1, w0
00085880  e06740b9   ldr     w0, [sp, #0x64 {var_c}]
00085884  2100000b   add     w1, w1, w0
00085888  008f9452   mov     w0, #0xa478
0008588c  40edba72   movk    w0, #0xd76a, lsl #0x10  {0xd76aa478}
00085890  2000000b   add     w0, w1, w0
00085894  e06700b9   str     w0, [sp, #0x64 {var_c_1}]
00085898  e06740b9   ldr     w0, [sp, #0x64 {var_c_1}]
0008589c  01648013   ror     w1, w0, #0x19
000858a0  e06340b9   ldr     w0, [sp, #0x60 {var_10}]
000858a4  2000000b   add     w0, w1, w0

joelreymont avatar May 14 '24 12:05 joelreymont

The stack according to IDA Pro

.text:000000000008575C var_70          = -0x70
.text:000000000008575C var_68          = -0x68
.text:000000000008575C data            = -0x58
.text:000000000008575C j               = -8
.text:000000000008575C i               = -4
.text:000000000008575C arg_0           =  0

vs the variables

unsigned __int64 v2; // t2
  int data[20]; // [xsp+18h] [xbp-58h]
  int j; // [xsp+68h] [xbp-8h]
  unsigned int i; // [xsp+6Ch] [xbp-4h]

joelreymont avatar May 14 '24 12:05 joelreymont

Also, where's the assignment to data[16] and how do I create uint32_t data[20] on the stack here?

Right now this has to be done manually (see https://github.com/Vector35/binaryninja-api/issues/2570). To do so you really should utilize the stack view, it makes validation easier. First you want to go to the stack view, identify the place you want to create it, in your case it is -0x58 (or var_58) and retype it as an array, you will get the following output:

00085830      int32_t var_58[0x14]
00085830      var_58[0x13] = *(arg1 + 0x50)
0008583c      var_58[0x12] = *(arg1 + 0x54)
00085848      var_58[0x11] = *(arg1 + 0x58)
00085854      var_58[0x10] = *(arg1 + 0x5c)
00085894      var_58[0x13] = ((var_58[0x12] & var_58[0x11]) | (not.d(var_58[0x12]) & var_58[0x10])) + var_58[0] + var_58[0x13] - 0x28955b88

emesare avatar May 14 '24 13:05 emesare

I don't have a stack view for some reason so I assumed that BN didn't have this functionality.

Will go figure out how to enable it...

Screenshot 2024-05-14 at 5 13 30 PM

joelreymont avatar May 14 '24 14:05 joelreymont

I don't have a stack view for some reason so I assumed that BN didn't have this functionality.

https://docs.binary.ninja/guide/index.html#stack

emesare avatar May 14 '24 14:05 emesare

It's doing the right thing now, thanks!

How do I get rid of - &__elf_program_headers[0].physical_address) in the assignment?

Also, note that data is declared after the loop that uses it. I think it ought to be before, just like i and j.

0008575c  struct MD5_CTX* DjiMd5_Transform(struct MD5_CTX* ctx_1, struct MD5_CTX* ctx_2)
00085768      int32_t i = 0
0008576c      int32_t j = 0
00085824      while (i u<= 0xf)
000857e4          uint32_t x0_21 = zx.d(ctx_2->data[zx.q(j)]) + (zx.d(ctx_2->data[zx.q(j + 1)]) << 8) + (zx.d(ctx_2->data[zx.q(j + 2)]) << 0x10) + (zx.d(ctx_2->data[zx.q(j + 3)]) << 0x18)
00085800          *(&data[zx.q(i)] - &__elf_program_headers[0].physical_address) = x0_21
0008580c          i += 1
00085818          j += 4
00085830      int32_t data[0x14]

joelreymont avatar May 14 '24 14:05 joelreymont

either mark it as not a pointer or rebase your binary.

plafosse avatar May 14 '24 14:05 plafosse

This is a proper ELF binary so I do have ELF

00000040  struct Elf64_ProgramHeader __elf_program_headers[0x9] = 
00000040  {
00000040      [0x0] = 
00000040      {
00000040          enum p_type type = PT_PHDR
00000044          enum p_flags flags = PF_R
00000048          uint64_t offset = 0x40
00000050          uint64_t virtual_address = 0x40
00000058          uint64_t physical_address = 0x40
00000060          uint64_t file_size = 0x1f8
00000068          uint64_t memory_size = 0x1f8
00000070          uint64_t align = 0x8
00000078      }

data is just an array of ints so no pointers.

&__elf_program_headers[0].physical_address resolves to 0x58.

IDA shows

    data[i++] = ctx_2->data[j] + (ctx_2->data[j + 1] << 8) + (ctx_2->data[j + 2] << 16) + (ctx_2->data[j + 3] << 24);

but BN shows

*(&data[zx.q(i)] - 0x58) =  ...

What am I missing?

Also, what do I need to mark as a non-pointer?

joelreymont avatar May 14 '24 15:05 joelreymont

This is a duplicate of this: https://github.com/Vector35/binaryninja-api/issues/5406 If we fix 5406 we'd not have this issue.

plafosse avatar May 21 '24 14:05 plafosse