Strange HLIL with a messed up stack and use of undefined variables
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
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
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]
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
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...
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
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]
either mark it as not a pointer or rebase your binary.
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?
This is a duplicate of this: https://github.com/Vector35/binaryninja-api/issues/5406 If we fix 5406 we'd not have this issue.