I am currently reversing a piece of malware but have become stuck. So far I have uncovered SSDT hooking and MajorFunction[] hooks, but the part I am stuck on is a unpacker for code that attaches itself onto services.exe. The unpacking is very straightforward (simple xoring) and the allocation of the virtual memory in services.exe is simple, but I am having trouble interpreting how memcpy translates to assembly. Also, I do not see how the ida hex-rays plugin generates some of the decimal indexes. I will post the full code below. The following is some of the questions I have:
In the assembly we have the following code:
.text:00010BF4 mov ebx, data_0E0h
...
.text:00010BFC lea ebx, Start_of_unpacking_address[ebx] ; ebx contains Start_of_unpacking_address[E0h]
...
.text:00010C28 movzx eax, word ptr [ebx+14h]
.text:00010C2C lea edx, [eax+ebx+18h]
.text:00010C30 movzx eax, word ptr [ebx+6]
.text:00010C34 and [ebp+services_exe_handle], 0 ; clear the handle to services.exe
.text:00010C38 lea ecx, [eax+eax*4]
.text:00010C3B shl ecx, 3
.text:00010C3E mov eax, offset Start_of_unpacking_address
.text:00010C43 sub ecx, eax
.text:00010C45 add ecx, edx
Hex-rays reports that this translates to the following:
v6 = (int)&v4[*((_WORD *)v4 + 10) + 24]; // pointer to 159C3
// Note that v4 + 10 = 1122A and the value at this location
// is 478B after unpacking. The dereferencing * uses this value.
// We then add 24 to it. This value is equal to 47A3. We then
// cast the location (&) of v4[0x47A3] to an int which is equal
// to (int) loc_159C3
//
v7 = *((_WORD *)v4 + 3); // equals 4C00h
I have been staring at the assembly for hours and still do not see how hex-rays gets this! Any explanation would be greatly appreciated!
Also, if you look at the assembly vs pseudo-c below, how does the memcpy reported in hex-rays correspond to the assembly? Again, help is greatly appreciated!
The following is the assembly:
.text:00010BCA ; int __stdcall unpack_and_put_in_memory(HANDLE services_exe_handle)
.text:00010BCA unpack_and_put_in_memory proc near ; CODE XREF: sub_10CDC+8Bp
.text:00010BCA
.text:00010BCA AllocationSize = dword ptr -0Ch
.text:00010BCA var_8 = dword ptr -8
.text:00010BCA BaseAddress = dword ptr -4
.text:00010BCA services_exe_handle= dword ptr 8
.text:00010BCA
.text:00010BCA mov edi, edi
.text:00010BCC push ebp
.text:00010BCD mov ebp, esp
.text:00010BCF sub esp, 0Ch
.text:00010BD2 mov ecx, data_1E000 ; off_1113c is an offset to 1E000
.text:00010BD2 ; ie we will unpack until eax = 1E000
.text:00010BD8 and [ebp+BaseAddress], 0
.text:00010BDC xor eax, eax
.text:00010BDE test ecx, ecx
.text:00010BE0 jbe short loc_10BF3
.text:00010BE2
.text:00010BE2 UNPACKING_FUNCTION: ; CODE XREF: unpack_and_put_in_memory+27j
.text:00010BE2 mov dl, Unpack_47h ; This is our unpacker!
.text:00010BE8 xor byte ptr Start_of_unpacking_address[eax], dl
.text:00010BEE inc eax
.text:00010BEF cmp eax, ecx
.text:00010BF1 jb short UNPACKING_FUNCTION
.text:00010BF3
.text:00010BF3 loc_10BF3: ; CODE XREF: unpack_and_put_in_memory+16j
.text:00010BF3 push ebx
.text:00010BF4 mov ebx, data_0E0h
.text:00010BFA push 40h ; Protect
.text:00010BFC lea ebx, Start_of_unpacking_address[ebx] ; ebx contains Start_of_unpacking_address[E0h]
.text:00010C02 mov eax, [ebx+50h]
.text:00010C05 push 3000h ; AllocationType
.text:00010C0A mov [ebp+AllocationSize], eax ; this will be 21000h that is loaded into AllocationSize
.text:00010C0D lea eax, [ebp+AllocationSize]
.text:00010C10 push eax ; AllocationSize
.text:00010C11 push 0 ; ZeroBits
.text:00010C13 lea eax, [ebp+BaseAddress]
.text:00010C16 push eax ; BaseAddress
.text:00010C17 push [ebp+services_exe_handle] ; ProcessHandle
.text:00010C1A call ds:ZwAllocateVirtualMemory ; We are calling this with a protect of PAGE_EXECUTE_READWRITE
.text:00010C1A ; A AllocationType of MEM_RESERVE | MEM_COMMIT which will reserve
.text:00010C1A ; the memory space, and make it accessible to the process.
.text:00010C1A ; It is 21000h in size.
.text:00010C1A ;
.text:00010C20 test eax, eax ; check if there is an error from the above call.
.text:00010C22 jl exit
.text:00010C28 movzx eax, word ptr [ebx+14h]
.text:00010C2C lea edx, [eax+ebx+18h]
.text:00010C30 movzx eax, word ptr [ebx+6]
.text:00010C34 and [ebp+services_exe_handle], 0 ; clear the handle to services.exe
.text:00010C38 lea ecx, [eax+eax*4]
.text:00010C3B shl ecx, 3
.text:00010C3E mov eax, offset Start_of_unpacking_address
.text:00010C43 sub ecx, eax
.text:00010C45 add ecx, edx
.text:00010C47 push esi
.text:00010C48 push edi
.text:00010C49 mov edi, [ebp+BaseAddress]
.text:00010C4C mov [ebp+var_8], edx
.text:00010C4F mov edx, ecx
.text:00010C51 shr ecx, 2
.text:00010C54 mov esi, eax
.text:00010C56 rep movsd
.text:00010C58 mov ecx, edx
.text:00010C5A and ecx, 3
.text:00010C5D rep movsb
.text:00010C5F cmp word ptr [ebx+6], 0
.text:00010C64 jbe short loc_10C9F
.text:00010C66 mov edx, [ebp+var_8]
.text:00010C69 add edx, 14h
.text:00010C6C mov [ebp+var_8], edx
.text:00010C6F
.text:00010C6F loc_10C6F: ; CODE XREF: unpack_and_put_in_memory+D3j
.text:00010C6F mov ecx, [edx-4]
.text:00010C72 mov esi, [edx]
.text:00010C74 mov edi, [edx-8]
.text:00010C77 add edi, [ebp+BaseAddress]
.text:00010C7A mov edx, ecx
.text:00010C7C shr ecx, 2
.text:00010C7F add esi, eax
.text:00010C81 rep movsd
.text:00010C83 mov ecx, edx
.text:00010C85 mov edx, [ebp+var_8]
.text:00010C88 and ecx, 3
.text:00010C8B inc [ebp+services_exe_handle]
.text:00010C8E rep movsb
.text:00010C90 movzx ecx, word ptr [ebx+6]
.text:00010C94 add edx, 28h
.text:00010C97 cmp [ebp+services_exe_handle], ecx
.text:00010C9A mov [ebp+var_8], edx
.text:00010C9D jb short loc_10C6F
.text:00010C9F
.text:00010C9F loc_10C9F: ; CODE XREF: unpack_and_put_in_memory+9Aj
.text:00010C9F mov ecx, [ebx+28h]
.text:00010CA2 mov eax, [ebp+BaseAddress]
.text:00010CA5 add ecx, eax
.text:00010CA7 pop edi
.text:00010CA8 mov Services_exe_our_base_memAddress, eax
.text:00010CAD mov Services_exe_our_base_someOffset, ecx
.text:00010CB3 xor eax, eax
.text:00010CB5 pop esi
.text:00010CB6
.text:00010CB6 exit: ; CODE XREF: unpack_and_put_in_memory+58j
.text:00010CB6 pop ebx
.text:00010CB7 leave
.text:00010CB8 retn 4
.text:00010CB8 unpack_and_put_in_memory endp
And the hex-rays pseudo-c output:
NTSTATUS __stdcall unpack_and_put_in_memory(HANDLE services_exe_handle)
{
unsigned int v1; // eax@1
void *v2; // ecx@1
NTSTATUS result; // eax@3
char *v4; // ebx@3
int v5; // edx@5
int v6; // edx@4
int v7; // eax@4
unsigned int v8; // ecx@6
int v9; // esi@6
void *v10; // edi@6
int v11; // edx@6
const void *v12; // esi@6
const void *v13; // esi@6
void *v14; // edi@6
int v15; // edx@6
unsigned int v16; // ecx@6
int v17; // ecx@7
PVOID BaseAddress; // [sp+8h] [bp-4h]@1
ULONG AllocationSize; // [sp+0h] [bp-Ch]@3
int v20; // [sp+4h] [bp-8h]@4
v2 = data_1E000;
BaseAddress = 0;
v1 = 0;
if ( data_1E000 )
{
do
{
Start_of_unpacking_address[v1] = Unpack_47h ^ (unsigned __int8)Start_of_unpacking_address[v1];
++v1;
}
while ( v1 < (unsigned int)v2 );
}
v4 = &Start_of_unpacking_address[data_0E0h];
AllocationSize = *(_DWORD *)&Start_of_unpacking_address[data_0E0h + 80];// AllocationSize is 21000h
result = ZwAllocateVirtualMemory(services_exe_handle, &BaseAddress, 0, &AllocationSize, 0x3000u, 0x40u);
if ( result >= 0 )
{
v6 = (int)&v4[*((_WORD *)v4 + 10) + 24]; // pointer to 159C3
// Note that v4 + 10 = 1122A and the value at this location
// is 478B after unpacking. The dereferencing * uses this value.
// We then add 24 to it. This value is equal to 47A3. We then
// cast the location (&) of v4[0x47A3] to an int which is equal
// to (int) loc_159C3
//
v7 = *((_WORD *)v4 + 3); // equals 4C00h
services_exe_handle = 0;
v20 = v6;
memcpy(BaseAddress, Start_of_unpacking_address, v6 + 40 * v7 - (_DWORD)Start_of_unpacking_address);
if ( *((_WORD *)v4 + 3) )
{
v5 = v20 + 20;
v20 += 20;
do
{
v8 = *(_DWORD *)(v5 - 4);
v9 = *(_DWORD *)v5;
v10 = (char *)BaseAddress + *(_DWORD *)(v5 - 8);
v11 = *(_DWORD *)(v5 - 4);
v8 >>= 2;
v12 = &Start_of_unpacking_address[v9];
memcpy(v10, v12, 4 * v8);
v13 = (char *)v12 + 4 * v8;
v14 = (char *)v10 + 4 * v8;
LOBYTE(v8) = v11;
v15 = v20;
++services_exe_handle;
memcpy(v14, v13, v8 & 3);
v16 = *((_WORD *)v4 + 3);
v5 = v15 + 40;
v20 = v5;
}
while ( (unsigned int)services_exe_handle < v16 );
}
v17 = (int)((char *)BaseAddress + *((_DWORD *)v4 + 10));
dword_2F194 = (int)BaseAddress;
dword_2F190 = v17;
result = 0;
}
return result;
}






