Re: [spam][crazy] bomb malware
this is what a gdb reg/asm layout looks like when copy-pasted into an email ┌─Register group: general────────────────────────────────────────────────────────────────────┐ │eax 0x0 0 │ │ecx 0x0 0 │ │edx 0x0 0 │ │ebx 0x0 0 │ │esp 0xffffc940 0xffffc940 ││ebp 0x0 0x0 ││esi 0x0 0 │ │edi 0x0 0 │ │eip 0x8048166 0x8048166 │ │eflags 0x246 [ PF ZF IF ] ││cs 0x23 35 │ │ss 0x2b 43 │└────────────────────────────────────────────────────────────────────────────────────────────┘│B+ 0x8048164 xor %ebp,%ebp │ │ > 0x8048166 pop %esi │ │ 0x8048167 mov %esp,%ecx │ │ 0x8048169 and $0xfffffff0,%esp │ │ 0x804816c push %eax │ │ 0x804816d push %esp ││ 0x804816e push %edx ││ 0x804816f push $0x804dbd6 │ │ 0x8048174 push $0x8048094 │ │ 0x8048179 push %ecx │ │ 0x804817a push %esi │ │ 0x804817b push $0x804a540 │ └────────────────────────────────────────────────────────────────────────────────────────────┘ native process 28422 In: L?? PC: 0x8048166 (gdb) layout regs (gdb) ni 0x08048166 in ?? () (gdb)
here it is skinny enough to see i don't usually use these views but they're fastest to find people reminding you of the commands to enable online ('layout asm', 'layout regs') up at the top are the registers of the process. the 'working memory'. they're lowercase now, instead of uppercase. then the next chunk has the disassembly of the function. i have a breakpoint (B+) on the first instruction and the cpu is about to execute the second at the bottom i typed 'ni' (next instruction) to move it to that second instruction. ┌─Register group: general──────────────────────────────────────────────┐ │eax 0x0 0 │ │ecx 0x0 0 │ │edx 0x0 0 │ │ebx 0x0 0 │ │esp 0xffffc940 0xffffc940 │ │ebp 0x0 0x0 │ │esi 0x0 0 │ │edi 0x0 0 │ │eip 0x8048166 0x8048166 │ │eflags 0x246 [ PF ZF IF ] │ │cs 0x23 35 │ │ss 0x2b 43 │ │ds 0x2b 43 │ ┌──────────────────────────────────────────────────────────────────────┐ │B+ 0x8048164 xor %ebp,%ebp │ │ > 0x8048166 pop %esi │ │ 0x8048167 mov %esp,%ecx │ │ 0x8048169 and $0xfffffff0,%esp │ │ 0x804816c push %eax │ │ 0x804816d push %esp │ │ 0x804816e push %edx │ │ 0x804816f push $0x804dbd6 │ │ 0x8048174 push $0x8048094 │ │ 0x8048179 push %ecx │ │ 0x804817a push %esi │ │ 0x804817b push $0x804a540 │ │ 0x8048180 call 0x804d23f │ └──────────────────────────────────────────────────────────────────────┘ native process 28422 In: L?? PC: 0x8048166 (gdb) layout regs (gdb) ni 0x08048166 in ?? () (gdb)
here i've repeatedly typed 'ni' to move it to the function call that initiates the mysterious behavior of the malware. you don't have to type 'ni' over and over again, gdb will assume you meant to type the same thing again if you just hit 'enter'. here, we don't want to type 'ni'. we'll type 'si' instead: 'step instruction'. this makes sure it gently steps into the function call, without puking out the entire thing waiting to get to the instruction following it, which is unlikely to be what would happen. ┌─Register group: general──────────────────────────────────────────────┐ │eax 0x0 0 ││ecx 0xffffc944 -14012 │ │edx 0x0 0 │ │ebx 0x0 0 ││esp 0xffffc920 0xffffc920 ││ebp 0x0 0x0 ││esi 0x1 1 │ │edi 0x0 0 │ │eip 0x8048180 0x8048180 │ │eflags 0x282 [ SF IF ] ││cs 0x23 35 ││ss 0x2b 43 │ │ds 0x2b 43 │ ┌──────────────────────────────────────────────────────────────────────┐ │ 0x804817b push $0x804a540 ││ > 0x8048180 call 0x804d23f │ │ 0x8048185 hlt │ │ 0x8048186 nop ││ 0x8048187 nop ││ 0x8048188 nop ││ 0x8048189 nop │ │ 0x804818a nop │ │ 0x804818b nop │ │ 0x804818c nop ││ 0x804818d nop │ │ 0x804818e nop │ │ 0x804818f nop │ └──────────────────────────────────────────────────────────────────────┘native process 28422 In: L?? PC: 0x8048180 0x0804816c in ?? () (gdb) ni 0x0804816d in ?? () (gdb) ni 0x0804816e in ?? () (gdb) ni 0x0804816f in ?? () (gdb) ni 0x08048174 in ?? () (gdb) ni 0x08048179 in ?? () (gdb) ni 0x0804817a in ?? () (gdb) ni 0x0804817b in ?? () (gdb) ni 0x08048180 in ?? () (gdb) [0] <h 19:bash 20:vim 21:gdb* Battery 100% | Tue 2021-12-14 07:33 -05
here it is after 'si'. something to remember when doing this is that it is a very old practice for binaries like this to detect whether or not they are being run in a conventional debugger. so this approach can only get you so far (and is very risky). ┌─Register group: general────────────────────────────────────────────┐ │eax 0x0 0 ││ecx 0xffffc944 -14012 │ │edx 0x0 0 │ │ebx 0x0 0 ││esp 0xffffc91c 0xffffc91c ││ebp 0x0 0x0 ││esi 0x1 1 │ │edi 0x0 0 │ │eip 0x804d23f 0x804d23f │ │eflags 0x282 [ SF IF ] ││cs 0x23 35 ││ss 0x2b 43 │ │ds 0x2b 43 │ ┌────────────────────────────────────────────────────────────────────┐ │ > 0x804d23f push %ebp ││ 0x804d240 push %edi │ │ 0x804d241 push %esi │ │ 0x804d242 push %ebx ││ 0x804d243 sub $0x8c,%esp ││ 0x804d249 mov 0xb8(%esp),%eax ││ 0x804d250 mov 0xa8(%esp),%edi │ │ 0x804d257 mov %eax,0x804e0b8 │ │ 0x804d25c mov 0xb4(%esp),%eax │ │ 0x804d263 mov %eax,0x804e0c8 ││ 0x804d268 mov 0xa4(%esp),%eax │ │ 0x804d26f mov 0xac(%esp),%ebp │ │ 0x804d276 lea (%edi,%eax,4),%edx │ └────────────────────────────────────────────────────────────────────┘native process 28422 In: L?? PC: 0x804d23f 0x0804816d in ?? () (gdb) ni 0x0804816e in ?? () (gdb) ni 0x0804816f in ?? () (gdb) ni 0x08048174 in ?? () (gdb) ni 0x08048179 in ?? () (gdb) ni 0x0804817a in ?? () (gdb) ni 0x0804817b in ?? () (gdb) ni 0x08048180 in ?? () (gdb) si 0x0804d23f in ?? () (gdb) [0] < 19:bash 20:vim 21:gdb* Battery 100% | Tue 2021-12-14 07:36 -05
so let's go back to ghidra, which probably has a debugger of its own even somewhere, and guess what this function will be doing before we step further through it.
The first thing I notice here is that the function takes a _lot_ of parameters. This is more poignant because it makes the assembly complex, but back in the entrypoint we saw what values were passed for each one of these parameters. ************************************************************** * * * FUNCTION * ************************************************************** int __cdecl FUN_0804d23f(undefined * param_1, int param_ int EAX:4 <RETURN> undefined * Stack[0x4]:4 param_1 XREF[1]: 0804d3e9(R) int Stack[0x8]:4 param_2 XREF[2]: 0804d268(R), 0804d3e2(R) uint * * Stack[0xc]:4 param_3 XREF[1]: 0804d250(R) undefined * Stack[0x10]:4 param_4 XREF[1]: 0804d26f(R) undefined4 Stack[0x14]:4 param_5 XREF[1]: 0804d372(R) undefined4 Stack[0x18]:4 param_6 XREF[1]: 0804d25c(R) undefined4 Stack[0x1c]:4 param_7 XREF[1]: 0804d249(R) undefined4 Stack[-0x14]:4 local_14 XREF[1]: 0804d32a(R) undefined4 Stack[-0x1c]:4 local_1c XREF[1]: 0804d323(R) undefined4 Stack[-0x24]:4 local_24 XREF[1]: 0804d31d(R) undefined4 Stack[-0x2c]:4 local_2c XREF[2]: 0804d2ed(R), 0804d314(R) undefined4 Stack[-0x54]:4 local_54 XREF[1]: 0804d2dc(R) undefined1 Stack[-0x88]:1 local_88 XREF[2]: 0804d290(*), 0804d2ce(*) undefined4 Stack[-0xac]:4 local_ac XREF[1]: 0804d3f0(*) FUN_0804d23f XREF[1]: entry:08048180(c) 0804d23f 55 PUSH EBP 0804d240 57 PUSH EDI 0804d241 56 PUSH ESI 0804d242 53 PUSH EBX 0804d243 81 ec 8c SUB ESP,0x8c 00 00 00 0804d249 8b 84 24 MOV EAX,dword ptr [ESP + param_7] b8 00 00 00 0804d250 8b bc 24 MOV EDI,dword ptr [ESP + param_3] a8 00 00 00 0804d257 a3 b8 e0 MOV [DAT_0804e0b8],EAX = ?? 04 08 0804d25c 8b 84 24 MOV EAX,dword ptr [ESP + param_6] b4 00 00 00 0804d263 a3 c8 e0 MOV [DAT_0804e0c8],EAX = ?? 04 08 0804d268 8b 84 24 MOV EAX,dword ptr [ESP + param_2] a4 00 00 00 0804d26f 8b ac 24 MOV EBP,dword ptr [ESP + param_4] ac 00 00 00 0804d276 8d 14 87 LEA EDX,[EDI + EAX*0x4] 0804d279 8d 42 04 LEA EAX,[EDX + 0x4] 0804d27c a3 bc e0 MOV [DAT_0804e0bc],EAX = ?? 04 08 0804d281 3b 07 CMP EAX,dword ptr [EDI] 0804d283 75 06 JNZ LAB_0804d28b 0804d285 89 15 bc MOV dword ptr [DAT_0804e0bc],EDX = ?? e0 04 08 LAB_0804d28b XREF[1]: 0804d283(j) 0804d28b 51 PUSH ECX
Here's where the entrypoint hands off control. It pushes function addresses and registers. It's rare for function addresses to be passed to other functions in mainstream code. In gdb, we can see what values all these parameters and registers have. 0804816c 50 PUSH param_1 0804816d 54 PUSH ESP=>local_8 0804816e 52 PUSH param_2 0804816f 68 d6 db PUSH FUN_0804dbd6 04 08 08048174 68 94 80 PUSH FUN_08048094 04 08 08048179 51 PUSH ECX 0804817a 56 PUSH ESI 0804817b 68 40 a5 PUSH FUN_0804a540 04 08 08048180 e8 ba 50 CALL FUN_0804d23f int FUN_0804d23f(undefined * par 00 00
i type 'run' into gdb to restart from the entrypoint param_1 is eax which is 0 esp=>local_8 is just plain esp.
param_2 is edx which is 0 that's the first three pushed values then the function pointers, two of them ecx here is 0xffffc944. I type `p *$ecx` into gdb and see it's a valid dereferencable pointer. wonder where this came from. glancing up at the entrypoint assembly 08048167 89 e1 MOV ECX,ESP 08048169 83 e4 f0 AND ESP,0xfffffff0 $ecx is $esp before being aligned to 16 bytes.
it was pleasant to add those bits we'll see whether and how this continues i have appointments and things today now
participants (1)
-
Karl