Zoom Icon

Carberp Reverse Engineering

From UIC Archive

Carberp from a Reverse Engineering Perspective


Carberp Reverse Engineering
Author: Evilcry
Email: [email protected]
Website: -
Date: 03/07/2011 (dd/mm/yyyy)
Level: Major skills are required
Language: English Flag English.gif
Comments: Comments, if you want


We are going to talk about Trojan Banker Carberp from a Reverse Engineering point of view. Carberp is a Botnet delivered in the usual ways of Blackmarket selling, designed to be a Trojan Spy and specifically a Banker similar to SpyEye and ZeuS, able to perform Man in the Browser attacks, steal victim credentials, kill antivirus softwares, remove other bots like SpyEye and Zeus and much more...

Tools & Files


Carberp is a Botnet delivered in the usual ways of Blackmarket selling, designed to be a Trojan Spy and specifically a Banker similar to SpyEye and ZeuS, able to:

  • Perform Man In The Browser
  • Steal Victim Machine Credentials
  • Kill AntiVirus Software
  • Remove Competitors Bots (SpyEye and ZeuS and others)
  • Plugin System
  • Screenshot Ability
  • Form Grabber
  • Backconnect

Works from XP to 7 even with limited accounts, and performs injections on IE, Firefox, Opera and Chrome.

Like the most famous Trojan Bankers, Carberp has a Plugin and Config structure, that during infection process are downloaded and decrypted by the bot, here a quick list of the most known plugins:

  • cfg/miniav.psd
  • cfg/stopav.psd
  • cfg/passw.psd

We have also a Configuration File that contains URL Triggers and Malicious JavaScript code to Inject.

The C&C server could present also the following additional files:

  • random_name.7z
  • /get/key.html
  • random_name.php3
  • w.php3
  • random_name.doc

Sample Generic Overview

The sample we are going to deal presents the following base characteristics

  • FileSize: 130.00 KB (133120 bytes)
  • MD5: C2D749950BFD092E5E3AD96EB64D4990
  • SHA1: 0C51FEC8397088F3E8AA7B9FDBF4DFB0EEF3D7BB
  • Sample: Carberbp (pass: infected)
  • Company Name: Lriptddh Bhybugb
  • Product Version:

The binary presents a layer of UPX compression.

Section Header is composed as usual by the following sections:

  • .UPX0
  • .UPX1
  • .rsrc

Code Entry Point is located at 000358E0 inside UPX1 section, ImportTable and Resources Directory are both placed into rsrc.

Preliminary Analysis

As you have seen from the previous paragraph the binary is packed with UPX, so the first obvious operation should be the usual unpacking.

But let's see what happens to the unpacked code, here is the Original Entry Point:

.text:004218A4 neg ecx .text:004218A6 or eax, eax .text:004218A8 jz loc_418615

As you can see, the start code is quite atypical, we have a conditional check, in our case jump is taken, this lead us to the following piece of code

.text:00418615 loc_418615: .text:00418615 neg esi .text:00418617 inc eax .text:00418618 retn  ; ExitProcess()

Aim is clear, eax drives the call flow, in this way we have a sort of Unpacking Awareness. Let's considerate the alternative branch solution, in other words we assume a NON zero value for EAX. Test can be quickly done by using IDA x86 Emulator plugin.

1 carb.jpg

EAX has a dummy value, now we can see that application correctly flows into a second layer of decryption. Following the way of manually changing register value is not secure, because entire stack and register values could affect the correct code flow o successive decryption stages. This implies that would be a good practice to follow code of the UPX packed sample.

2 carb.jpg

The picture above shows UPX packed structure of the executable, it's also pretty trivial to identify in the last block the jmp to the OEP, alias the previously seen code.

In this way, we are now able to continue the code flow analysis without the risk of incongruences. Here also a view of the second layer call flow.

3 carb.jpg

We will keep an eye on the evolution of the code flow during the various decryption layers.

.text:004218BD db 0 .text:004218BE db 0 .text:004218BF db 0 .text:004218C0 neg esi .text:004218C2 adc ecx, esi .text:004218C4 sbb ecx, edi .text:004218C6 inc edx .text:004218C7 dec esi .text:004218C8 inc ecx .text:004218C9 db 0 .text:004218CA db 0

We meet here a very long sequence of 0 opcodes and repeated pieces of code as you can see above.

Code can be seen from two points of view now:

   * Direct Analysis
   * Higher Abstraction Level

Second point implies some assumption to be done, this allow us to see the code from an higher perspective. Assuming that there are no pieces of SMC code, to break the flow we could have:

   * Jumps
   * RETs

Further observation will confirm the presence of a final jump, code is structure as follow:

  • Zero_Opcode_Padding
  • Real_Code
  • Zero_Opcode_Padding
  • Jmp to the Next Block

What we gain from this pattern? should be easy to understand, how to speed up debugging process by looking directly for jmp instruction. For some people this could be an obvious observation, here I wanted to show the process that lead us to such conclusions.

After traversing all these chained blocks we land to the following piece of code:

.text:0041AE3D push ebp .text:0041AE3E mov ebp, esp .text:0041AE40 sub esp, 28h .text:0041AE43 lea edx, [ebp+var_18] .text:0041AE46 push edx .text:0041AE47 push 6241726Bh .text:0041AE4C push eax .text:0041AE4D push [ebp+var_8] .text:0041AE50 push 6B4E4144h .text:0041AE55 lea edx, [ebp+var_14] .text:0041AE58 push edx .text:0041AE59 push [ebp+var_4] .text:0041AE5C push offset dword_426938 .text:0041AE61 push [ebp+var_1C] .text:0041AE64 push ecx .text:0041AE65 call sub_42C19C .text:0041AE6A add eax, ebx .text:0041AE6C add esp, 1610h .text:0041AE72 sub eax, ecx .text:0041AE74 adc eax, ecx .text:0041AE76 jmp loc_41A435  ; Next Block

Due to the change of code structure we can identify here a Third Layer of Decryption. Respect to the previous block we have an additional element, that affects code flow, is the CALL. The code that follows is composed by several nested calls.

After that bundle of calls, we can see some api call performed in the following way:

RETN ; GetModuleHandleW LEAVE RETN ; True RET

Function GetModuleFileNameW is called indirectly. In the same way is called a VirtualAlloc that will host another decryption layer, with a new kind of obfuscation.

003B4BE8 55 PUSH EBP 003B4BE9 8BEC MOV EBP,ESP 003B4BEB ^ E9 5AFEFFFF JMP 003B4A4A .. 003B13FE 03E0 ADD ESP,EAX 003B1400 E9 0B3D0000 JMP 003B5110 .. 003B1B3B 32EE XOR CH,DH 003B1B3D BB A0860100 MOV EBX,186A0 003B1B42 E9 0C070000 JMP 003B2253 .. 003B53E5 0BDB OR EBX,EBX 003B53E7 ^ E9 63C3FFFF JMP 003B174F .. 003B0448 0F85 53380000 JNE 003B3CA1 003B044E E9 58060000 JMP 003B0AAB

The structure is pretty clear:

  • Real_Code
  • Jmp
  • Real_Code
  • Jmp

Following a block of code like this could be a bit messy, especially on jmp based loops, in that case just locate:

  • Conditional_Jump
  • Jmp

and place a breakpoint on Jmp.

This was the last spaghetti code layer, finally we land to the unpacked and active infection layer.

Core Infection

0040F860 55 PUSH EBP 0040F861 8BEC MOV EBP,ESP 0040F863 81EC 18020000 SUB ESP,218 0040F869 E8 82590000 CALL 004151F0 0040F86E 68 04010000 PUSH 104 0040F873 8D85 F0FDFFFF LEA EAX,[EBP-210] 0040F879 50 PUSH EAX 0040F87A 6A 00 PUSH 0 0040F87C E8 8FBFFFFF CALL 0040B810 0040F881 83C4 0C ADD ESP,0C 0040F884 8D8D F0FDFFFF LEA ECX,[EBP-210] 0040F88A 51 PUSH ECX 0040F88B E8 F06CFFFF CALL 00406580

This can be considered the True EntryPoint, in other words here starts the Infection Process.

Let's see the call flow graph of the core infection executable:

4 carb.jpg

As you can see from the above graph, structure of the malicious code can be divided in 4 regions, each one identified by a different color rectangle.

The most interesting thing that we can observe is that after the first region, we have a bifurcation of the code path, and finally a common ending region. The double path as you can see, does not have intersection points except Start and End regions. This means the code flow could take two different ways of execution. Without going too deep in explanation, we should formulate two basic questions in order to achieve a complete functional and technical understanding.

   * What's the condition that determine the path ?
   * What are the differences between the two path ?

We can immediately identify who determines the path, simply by looking better at the final zone of the start region:

5 carb.jpg

call sub_406240 affects the EAX value, that will influence the code flow.

The second question to be answered, obviously, implies that we need to debug both branches.

The main routine does not uses directly Function Addresses, we will meet always the following construct:

0040B813 51 PUSH ECX 0040B814 68 FE934377 PUSH 774393FE ; Hash Function Identifier 0040B819 6A 01 PUSH 1 0040B81B 6A 00 PUSH 0 0040B81D E8 0EDFFFFF CALL 00409730 ; Resolve Function 0040B822 83C4 0C ADD ESP,0C 0040B825 8945 FC MOV DWORD PTR SS:[EBP-4],EAX 0040B828 8B45 10 MOV EAX,DWORD PTR SS:[EBP+10] 0040B82B 50 PUSH EAX 0040B82C 8B4D 0C MOV ECX,DWORD PTR SS:[EBP+0C] 0040B82F 51 PUSH ECX 0040B830 8B55 08 MOV EDX,DWORD PTR SS:[EBP+8] 0040B833 52 PUSH EDX 0040B834 FF55 FC CALL DWORD PTR SS:[EBP-4] ; Call Function

We have an hash, given by the third parameter that identifies unequivocally the function that need to be called, call 00409730 returns the address of the specified function and successively is called. In this case we have a GetModuleFileNameW.

The core point of Carberp functionalities can be summarized in one call.

UPX0:0040F9DF call sub_40A580  ; Code Injection UPX0:0040F9E4 add esp, 4 UPX0:0040F9E7 movzx ecx, al UPX0:0040F9EA test ecx, ecx UPX0:0040F9EC jnz short loc_40FA1B UPX0:0040F9EE mov ds:dword_42B928, 0 UPX0:0040F9F8 push offset sub_40F810 UPX0:0040F9FD call sub_40A5F0 UPX0:0040FA02 add esp, 4 UPX0:0040FA05 movzx edx, al UPX0:0040FA08 test edx, edx UPX0:0040FA0A jnz short loc_40FA1B UPX0:0040FA0C lea eax, [ebp+var_210] UPX0:0040FA12 push eax UPX0:0040FA13 call sub_406470  ; ExitProcess

First call, contains entire code injection routine that will target explorer.exe

  # explorer.exe path is resolved
  # CreateProcess of explorer, with creation flag CREATE_SUSPENDED
  # Create a Map View of the File
  # Map View of the Section
  # NtQueueApcThread
  # NtResumeThread

At this point code injection is completed and dropper ends its function.

Catching the Injection

As previously seen, to continue infection Carberp performs an Injection by creating a suspended explorer.exe process and mapping successively a view. We obviously need to keep track of the injected code, but we are in front of a Child Process created by main carberp executable which resides in suspended state.

The situation we have pose two problems:

   * The Process does not Appear in the Process List
   * Problems in Attaching a Debugger.

Here the plan, we reach NtResumeThread, so we are sure that all is ready for execution, patch the malicious injected code with a classical 0xEBFE which means an endless jump over itself, and finally let the process run. The process will be now running, and available into the process list like every other process, both problems posed above are now solved.

But, how we can know the address where to inject our 'EBFE' ? As you have previously seen the third parameter of ZwMapViewOfSection is BaseAddress, a pointer to a variable that receives the base address of the view.

Keeping an eye over this variable, at NtResumeThread we have the correct value where to place the patch. We can use Olly Advanced plugin ( Process Patcher ) to apply our modifications, here a screenshot:

6 carb.JPG

Now process is ready to be resumed and debugged, so we can execute NtResumeThread. This is the situation seen from Process Explorer:

7 carb.JPG

The second explorer as you can see produces an high consumption of CPU, this is caused by the endless loop we placed on the top of the code. We can now attach a debugger to the process, we land here:

0009F810 EB FE JMP SHORT 0009F810 0009F812 EC IN AL,DX 0009F813 E8 D8590000 CALL 000A51F0 0009F818 833D 28B94200 0 CMP DWORD PTR DS:[42B928],0 0009F81F 74 2D JE SHORT 0009F84E 0009F821 C705 28B94200 0 MOV DWORD PTR DS:[42B928],0 0009F82B 68 10F84000 PUSH 40F810 0009F830 E8 BBADFFFF CALL 0009A5F0 0009F835 83C4 04 ADD ESP,4 0009F838 0FB6C0 MOVZX EAX,AL 0009F83B 85C0 TEST EAX,EAX 0009F83D 75 05 JNE SHORT 0009F844 0009F83F E8 2CFFFFFF CALL 0009F770 0009F844 6A 01 PUSH 1 0009F846 E8 151CFFFF CALL 00091460 0009F84B 83C4 04 ADD ESP,4 0009F84E E8 1DFFFFFF CALL 0009F770 0009F853 33C0 XOR EAX,EAX 0009F855 5D POP EBP 0009F856 C2 0400 RETN 4

Now we can restore the original bytes -> 0x558B but before committing the patch we have to place a breakpoint in the location immediately after the Prelude, or the code will run automatically immediately after changing the bytes.

The freshly injected code, drops a copy of the main dropper (the packed one) into automatic execution directory under the name of igfxtray.exe. Code performs also api hooking (presented in the next paragraph) and completes injection by downloading and decrypting configuration and plugins.

Revealing Hooks via Windbg

We can use WinDbg to discover hooks installed by Carberp in a very easy way. As you have seen, the trojan injects code into Explorer.exe process, this implies that in explorer.exe address space we will have traces of infection, a Full Dump can be taken via Process Explorer.

At this point we can enumerate all module and look for differences between functions in the dump and relative symbol in the following way:

> !for_each_module !chkimg @#ModuleName -d

Here what we have

DBGHELP: C:\WinDDK\7600.16385.1\Debuggers\sym\wininet.dll\41252C1Ba7000\wininet.dll - OK

   77194ac5-77194ac9  5 bytes - wininet!HttpOpenRequestA

[ 8b ff 55 8b ec:e9 06 69 f7 89 ]

   771961dc-771961e0  5 bytes - wininet!InternetCloseHandle (+0x1717)

[ 8b ff 55 8b ec:e9 5f 51 f7 89 ]

   771976b8-771976bc  5 bytes - wininet!HttpSendRequestA (+0x14dc)

[ 8b ff 55 8b ec:e9 03 3b f7 89 ]

   77199555-77199559  5 bytes - wininet!InternetReadFile (+0x1e9d)

[ 8b ff 55 8b ec:e9 26 1d f7 89 ]

   771a325f-771a3263  5 bytes - wininet!InternetQueryDataAvailable (+0x9d0a)

[ 8b ff 55 8b ec:e9 ac 80 f6 89 ]

   771a53eb-771a53ef  5 bytes - wininet!HttpSendRequestExW (+0x218c)

[ 8b ff 55 8b ec:e9 60 5e f6 89 ]

   771a6345-771a6349  5 bytes - wininet!HttpOpenRequestW (+0xf5a)

[ 8b ff 55 8b ec:e9 c6 50 f6 89 ]

   771c7e9a-771c7e9e  5 bytes - wininet!InternetReadFileExA (+0x21b55)

[ 8b ff 55 8b ec:e9 11 34 f4 89 ]

   771c88d6-771c88dd  8 bytes - wininet!InternetWriteFileExW (+0xa3c)

[ 6a 78 ff 15 34 14 18 77:e9 05 2a f4 89 90 90 90 ]

   771e1808-771e180c  5 bytes - wininet!HttpSendRequestW (+0x18f32)

[ 8b ff 55 8b ec:e9 e3 99 f2 89 ]

   771e190d-771e1911  5 bytes - wininet!HttpSendRequestExA (+0x105)

[ 8b ff 55 8b ec:e9 0e 99 f2 89 ] 58 errors : wininet (77194ac5-771e1911)

Meaning should be clear, wininet modules presents some 'errors', more specifically some differences between functions in memory and the ones used as symbols.

Let's inspect the code of HttpOpenRequestA

0:000> u 77194ac5 wininet!HttpOpenRequestA: 77194ac5 e90669f789 jmp 0110b3d0 77194aca 83ec5c sub esp,5Ch 77194acd a1189a2077 mov eax,dword ptr [wininet!__security_cookie (77209a18)] 77194ad2 8945fc mov dword ptr [ebp-4],eax 77194ad5 8b4510 mov eax,dword ptr [ebp+10h] 77194ad8 8945c0 mov dword ptr [ebp-40h],eax 77194adb 8b4514 mov eax,dword ptr [ebp+14h] 77194ade 8945c4 mov dword ptr [ebp-3Ch],eax

As you can see, first instruction is a jump to a suspicious location, this piece of code clearly demonstrates the presence of an hook. We can know more about this location

0:000> !address 0110b3d0 Usage: <unclassified> Allocation Base: 00000000 Base Address: 01100000 End Address: 0112d000 Region Size: 0002d000 Type: 00000000 State: 00000000 Protect: 00000000

In this way we know where Starts and Ends the piece of code responsible of handling hooks. These are two precious informations, especially the first one, because we have a range where to look for memory mapped executables.

0:000> s -a 01100000 l0112d000/4 "MZ" 01100000 4d 5a 90 00 03 00 00 00-04 00 00 00 ff ff 00 00 MZ..............

The presence of "MZ" obviously is Necessary but NOT Sufficient condition to say that this is an executable, we need more proofs. These can be obtained by checking the validity of executable presumably located at 01100000.

0:000> !dh -a 01100000 File Type: EXECUTABLE IMAGE FILE HEADER VALUES

    14C machine (i386)
      4 number of sections

4DD1BAAC time date stamp Tue May 17 02:00:44 2011

      0 file pointer to symbol table
      0 number of symbols
     E0 size of optional header
    102 characteristics
           32 bit word machine

This is an Executable. Now let's suppose that we want to carve it from memory, how to do ?

0:000> .writemem carved_from_explorer 01100000 0112d000 Writing 2d001 bytes....

The injected executable contains Hook Handlers and Routines to Deal with Captured data.

Carberp Analysis via Volatility

Identification of the System

  1. python vol.py imageinfo -f carberp.dmp

Volatile Systems Volatility Framework 2.1_alpha

         Suggested Profile(s) : WinXPSP3x86, WinXPSP2x86 (Instantiated with WinXPSP2x86)
                    AS Layer1 : JKIA32PagedMemory (Kernel AS)
                    AS Layer2 : FileAddressSpace (/home/.../carberp.dmp)
                     PAE type : No PAE
                          DTB : 0x39000
                         KDBG : 0x8054c760L
                         KPCR : 0xffdff000L
            KUSER_SHARED_DATA : 0xffdf0000L
          Image date and time : 2011-09-24 15:18:26 
    Image local date and time : 2011-09-24 15:18:26 
         Number of Processors : 1
                   Image Type : Service Pack 2

We are dealing with a Windows XP on x86 Platform with Service Pack 2.

Process Enumeration

  1. python vol.py pslist -f carberp.dmp

Volatile Systems Volatility Framework 2.1_alpha

Offset(V)  Name                 PID    PPID   Thds   Hnds   Time 

-------------------- ------ ------ ------ ------ -------------------

0x812ed020 System 4 0 54 255 1970-01-01 00:00:00 0xffb43020 smss.exe 368 4 3 21 2011-09-24 14:14:38 0xffb9ada0 csrss.exe 584 368 11 375 2011-09-24 14:14:39 0xffb8f488 winlogon.exe 608 368 18 438 2011-09-24 14:14:39 0x811b42e0 services.exe 652 608 15 255 2011-09-24 14:14:39 0x811655d0 lsass.exe 664 608 20 333 2011-09-24 14:14:39 0xffafb560 VBoxService.exe 824 652 8 107 2011-09-24 14:14:40 0xffaf42a0 svchost.exe 868 652 20 201 2011-09-24 14:14:40 0xffb01980 svchost.exe 956 652 9 228 2011-09-24 14:14:40 0xffaeda18 svchost.exe 1052 652 61 1138 2011-09-24 14:14:41 0xffae5458 svchost.exe 1112 652 6 91 2011-09-24 14:14:41 0xffb60da0 svchost.exe 1172 652 13 204 2011-09-24 14:14:42 0xffb6eca8 explorer.exe 1480 1404 14 355 2011-09-24 14:14:43 0xffae41c8 spoolsv.exe 1604 652 11 110 2011-09-24 14:14:44 0xffaef788 alg.exe 500 652 5 101 2011-09-24 14:14:59 0xffb2ea78 ctfmon.exe 540 1480 1 66 2011-09-24 14:14:59 0xffb31650 wscntfy.exe 588 1052 1 36 2011-09-24 14:15:00 0xffaef020 svchost.exe 1132 1480 4 58 2011-09-24 15:17:32 0x811bcd60 svchost.exe 984 1480 1 39 2011-09-24 15:17:32 0xffb53da0 svchost.exe 1212 1480 0 ------ 2011-09-24 15:17:32 0x811ea258 firefox.exe 1332 1480 25 272 2011-09-24 15:17:45

These informations are enough to make some speculation and obtain an investigation direction.

As you can see we have various svchost.exe processes, the first 4 have a Parent PID (652) that belongs to services.exe PID (652) with a time of 14:14:40/41/42.

Successively you can see other 3 svchost.exe processes, but this time Parent PID is different (1480) that belongs to explorer.exe (PID= 1480), additionally these processes have the same Timing 15:17:32.

This basically means that there are some implications connected to explorer.exe that needs further investigations.

Due to the fact that our suspects are on svchost.exe, actively involved into network activity of a system, let's scan physical memory for _TCPT_OBJECT objects (tcp connections) via

  1. python vol.py connscan -f carberp.dmp

Volatile Systems Volatility Framework 2.1_alpha

Offset(P)  Local Address             Remote Address            Pid   

------------------------- ------------------------- ------

0x0106b6e0 984 0x010a3008 1212 0x01108008 1332 0x028ab008 1332 0x03656568 1332 0x03d9e9e8 1132 0x03de2008 1332 0x03e26598 1332 0x06a1ac10 1132 0x06a65008 1332 0x06a66008 1332 0x07a13b58 1332 0x08a33008 1332 0x0acd0008 1332

As you can see activity pertains mainly to Firefox (PID: 1332); we have also PID 984 and 1212 (suspect svchost) that aren't of great help and finally

0x06a1ac10 1132

Where we have an interesting IP that belongs to a suspect svchost.

Looking for lead us to an interesting result:

the IP is malicious, belongs to Carberp ( 08C01BBE430F9FEA1A532DFD13F2836A )

Proven that svchost is malicious, due to its strict relationship with explorer.exe we are allowed to think that Carberp performed code injection.

Here comes a great and really handy plugin for Volatility called malfind.

  1. python vol.py malfind -f carberp.dmp -p 1480 -D /home/../vol_dumps

Name Pid Start End Tag Hits Protect explorer.exe 1480 0x01a70000 0x1a70fff0 VadS 0 PAGE_EXECUTE_READWRITE Dumped to: /home/../vol_dumps/explorer.exe.7585ca8.01a70000-01a70fff.dmp 0x01a70000 8b ff 55 8b ec e9 a9 e2 2a 76 00 00 00 00 00 00 ..U.....*v...... 0x01a70010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0x01a70020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0x01a70030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0x01a70040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0x01a70050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0x01a70060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0x01a70070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................

Disassembly: 01a70000: 8bff MOV EDI, EDI 01a70002: 55 PUSH EBP 01a70003: 8bec MOV EBP, ESP 01a70005: e9a9e22a76 JMP 0x77d1e2b3 01a7000a: 0000 ADD [EAX], AL 01a7000c: 0000 ADD [EAX], AL 01a7000e: 0000 ADD [EAX], AL 01a70010: 0000 ADD [EAX], AL 01a70012: 0000 ADD [EAX], AL 01a70014: 0000 ADD [EAX], AL

explorer.exe 1480 0x01a00000 0x1a00fff0 VadS 0 PAGE_EXECUTE_READWRITE Dumped to: /home/../vol_dumps/explorer.exe.7585ca8.01a00000-01a00fff.dmp 0x01a00000 8b ff 55 8b ec e9 d7 61 79 75 00 00 00 00 00 00 ..U....ayu...... 0x01a00010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0x01a00020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0x01a00030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0x01a00040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0x01a00050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0x01a00060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0x01a00070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................

Disassembly: 01a00000: 8bff MOV EDI, EDI 01a00002: 55 PUSH EBP 01a00003: 8bec MOV EBP, ESP 01a00005: e9d7617975 JMP 0x771961e1 01a0000a: 0000 ADD [EAX], AL 01a0000c: 0000 ADD [EAX], AL 01a0000e: 0000 ADD [EAX], AL 01a00010: 0000 ADD [EAX], AL 01a00012: 0000 ADD [EAX], AL 01a00014: 0000 ADD [EAX], AL

malfind automatically locates and extract suspicious memory regions ( injected code ); dumped content is placed into /vol_dump, you must create an output directory for malfind.

Besides all the entries printed out during scan process let's check the first entry saved into /vol_dump, explorer.exe.7585ca8.00e20000-00e5afff.dmp

Start Address is 0x00e20000, here its content

0x00e20000 4d 5a 90 00 03 00 00 00 04 00 00 00 ff ff 00 00 MZ.............. 0x00e20010 b8 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 [email protected] 0x00e20020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0x00e20030 00 00 00 00 00 00 00 00 00 00 00 00 c8 00 00 00 ................ 0x00e20040 0e 1f ba 0e 00 b4 09 cd 21 b8 01 4c cd 21 54 68 ........!..L.!Th 0x00e20050 69 73 20 70 72 6f 67 72 61 6d 20 63 61 6e 6e 6f is.program.canno 0x00e20060 74 20 62 65 20 72 75 6e 20 69 6e 20 44 4f 53 20 t.be.run.in.DOS. 0x00e20070 6d 6f 64 65 2e 0d 0d 0a 24 00 00 00 00 00 00 00 mode....$....... 0x00e20080 da 83 9c 2b 9e e2 f2 78 9e e2 f2 78 9e e2 f2 78 ...+...x...x...x 0x00e20090 b9 24 89 78 9b e2 f2 78 9e e2 f3 78 88 e2 f2 78 .$.x...x...x...x 0x00e200a0 80 b0 76 78 a2 e2 f2 78 80 b0 63 78 9f e2 f2 78 ..vx...x..cx...x 0x00e200b0 52 69 63 68 9e e2 f2 78 00 00 00 00 00 00 00 00 Rich...x........ 0x00e200c0 00 00 00 00 00 00 00 00 50 45 00 00 4c 01 04 00 ........PE..L... 0x00e200d0 78 8b f6 4d 00 00 00 00 00 00 00 00 e0 00 0f 01 x..M............ 0x00e200e0 0b 01 09 00 00 70 02 00 00 10 01 00 00 00 00 00 .....p.......... 0x00e200f0 80 a5 01 00 00 10 00 00 00 80 02 00 00 00 40 00 [email protected]

Let's take a list of the strings that appears into the executable

  1. strings explorer.exe.7585ca8.00e20000-00e5afff.dmp >> strings.txt

Rapport has been found! Trying to kill... C:\anti_rapport_dll.dll .. /cfg/stopav.plug /cfg/miniav.plug .. GET /stat?uptime=%d&downlink=%d&uplink=%d&id=%s&statpass=%s&comment=%s HTTP/1.0 >>>>>> Inject URL=%s ...

These strings clearly indicates that malfind correctly catched the malicious executable injected.

It's important to say that in this phase of analysis VAD (Virtual Address Descriptor) could give pretty interesting hints. We have four plugins that deals with VAD vadwalk, vadinfo, vadtree, vaddump. Let's see usage of vadinfo

  1. python vol.py vadinfo -f carberp.dmp -p 1480

VAD node @81137098 Start 00e20000 End 00e5afff Tag VadS Flags: MemCommit, PrivateMemory Commit Charge: 59 Protection: 6

The VAD entry I've chosen to show belongs to the memory range in which stands the executable previously carved, as you can see informations indicates a Protection of 6 belongs PAGE_EXECUTE_READWRITE.

As we know, Carberp is a Banking trojan which performs Web Code Injections, this means that we should find traces of its presence into the Browser Process.

  1. python vol.py apihooks -f carberp.dmp -p 1332

Volatile Systems Volatility Framework 2.1_alpha Name Type Target Value firefox.exe[1332] inline nspr4.dll!PR_Close[0x375bc0L] 0x375bc0 JMP 0x15f0f0 (UNKNOWN) firefox.exe[1332] inline nspr4.dll!PR_DestroyPollableEvent[0x375bc0L] 0x375bc0 JMP 0x15f0f0 (UNKNOWN) firefox.exe[1332] inline nspr4.dll!PR_OpenTCPSocket[0x389a50L] 0x389a50 JMP 0x15f140 (UNKNOWN) firefox.exe[1332] inline nspr4.dll!PR_Read[0x373160L] 0x373160 JMP 0x15ef30 (UNKNOWN) firefox.exe[1332] inline nspr4.dll!PR_Write[0x373170L] 0x373170 JMP 0x15f000 (UNKNOWN) firefox.exe[1332] syscall ntdll.dll!NtAcceptConnectPort[0x7c91d379L] 0x7ffe0300 MOV EDX, 0x7ffe0300 (UNKNOWN) firefox.exe[1332] syscall ntdll.dll!NtAccessCheck[0x7c91d38eL] 0x7ffe0300 MOV EDX, 0x7ffe0300 (UNKNOWN) firefox.exe[1332] syscall ntdll.dll!NtAccessCheckAndAuditAlarm[0x7c91d3a3L] 0x7ffe0300 MOV EDX, 0x7ffe0300 (UNKNOWN) firefox.exe[1332] syscall ntdll.dll!NtAccessCheckByType[0x7c91d3b8L] 0x7ffe0300 MOV EDX, 0x7ffe0300 (UNKNOWN) firefox.exe[1332] syscall ntdll.dll!NtAccessCheckByTypeAndAuditAlarm[0x7c91d3cdL] 0x7ffe0300 MOV EDX, 0x7ffe0300 (UNKNOWN) firefox.exe[1332] syscall ntdll.dll!NtAccessCheckByTypeResultList[0x7c91d3e2L] 0x7ffe0300 MOV EDX, 0x7ffe0300 (UNKNOWN) ...

As you can see first 5 entries are classical inline hooks on the most common APIs used to intercept and modify user's browsing activity. Successively we have some 'syscall' hooking type, further investigations can be done by using another Volatility plugin, called volshell plugin.

Inline hook Sample

  1. python vol.py volshell -f carberp.dmp

Volatile Systems Volatility Framework 2.1_alpha Current context: process System, pid=4, ppid=0 DTB=0x39000 Welcome to volshell! Current memory image is: file:///home/../carberp.dmp To get help, type 'hh()' >>> cc(pid=1332) Current context: process firefox.exe, pid=1332, ppid=1480 DTB=0x2c4e000 >>> dis(0x375bc0) 0x375bc0 e92b95deff JMP 0x15f0f0 0x375bc5 90 NOP 0x375bc6 89442404 MOV [ESP+0x4], EAX 0x375bca 8b5104 MOV EDX, [ECX+0x4] 0x375bcd ffe2 JMP EDX 0x375bcf cc INT 3 0x375bd0 8b442404 MOV EAX, [ESP+0x4] 0x375bd4 8b4804 MOV ECX, [EAX+0x4] 0x375bd7 8b01 MOV EAX, [ECX] 0x375bd9 8b10 MOV EDX, [EAX] 0x375bdb 6a01 PUSH 0x1 0x375bdd 68c93a3900 PUSH DWORD 0x393ac9 0x375be2 50 PUSH EAX 0x375be3 8b420c MOV EAX, [EDX+0xc] 0x375be6 ffd0 CALL EAX 0x375be8 83e801 SUB EAX, 0x1 0x375beb 83c40c ADD ESP, 0xc 0x375bee f7d8 NEG EAX 0x375bf0 1bc0 SBB EAX, EAX 0x375bf2 c3 RET

Syscall Hook Sample

>>> dis(0x7c91d379) 0x7c91d379 b800000000 MOV EAX, 0x0 0x7c91d37e ba0003fe7f MOV EDX, 0x7ffe0300 0x7c91d383 ff12 CALL DWORD [EDX] 0x7c91d385 c21800 RET 0x18 0x7c91d388 90 NOP 0x7c91d389 90 NOP

Where 0x7FFE0300 is a pointer to KiFastSystemCall

Further informations here http://www.honeynet.org/node/578

Now we can check for Registry and FileSystem presence of Carberp in the victim system.

Usually malicious applications uses registry to ensure survival (malware execution) on system restart.

This can be done via printkey plugin in the following way.

  1. python vol.py printkey -f carberp.dmp -K "Software\Microsoft\Windows\CurrentVersion\Run"

Volatile Systems Volatility Framework 2.1_alpha Legend: (S) = Stable (V) = Volatile

Registry: \Device\HarddiskVolume1\Documents and Settings\-\NTUSER.DAT Key name: Run (S) Last updated: 2011-09-24 11:45:07


Values: REG_SZ CTFMON.EXE  : (S) C:\WINDOWS\system32\ctfmon.exe

Registry: \Device\HarddiskVolume1\Documents and Settings\NetworkService\NTUSER.DAT Key name: Run (S) Last updated: 2011-09-24 06:31:50



Registry: \Device\HarddiskVolume1\Documents and Settings\LocalService\NTUSER.DAT Key name: Run (S) Last updated: 2011-09-24 06:31:50



We have only ctfmon.exe as entry, nothing interesting, we can now look directly into the filesystem for some suspicious entry. This can be accomplished by using filescan plugin that enumerates _FILE_OBJECT pool allocations.

  1. python vol.py filescan -f carberp.dmp | grep automatica

Volatile Systems Volatility Framework 2.1_alpha 0x01114948 1 1 R--r-- '\\Documents and Settings\\-\\Menu Avvio\\Programmi\\Esecuzione automatica\\igfxtray.exe' 0x023b8948 1 1 R--r-- '\\Documents and Settings\\-\\Menu Avvio\\Programmi\\Esecuzione automatica\\igfxtray.exe' 0x08f50180 1 0 -WD--- '\\Documents and Settings\\-\\Menu Avvio\\Programmi\\Esecuzione automatica\\igfxtray.exe'

igfxtray.exe it's exactly the name that Carberp uses to copy itself into automatic execution directory.


According to the title, the main scope of this blog post, is not a complete functional analysis (that will be covered in another one) but a simple view of the 'problem carberp' under a reverse engineering point of view.

Final Notes

Final Notes



I documenti qui pubblicati sono da considerarsi pubblici e liberamente distribuibili, a patto che se ne citi la fonte di provenienza. Tutti i documenti presenti su queste pagine sono stati scritti esclusivamente a scopo di ricerca, nessuna di queste analisi è stata fatta per fini commerciali, o dietro alcun tipo di compenso. I documenti pubblicati presentano delle analisi puramente teoriche della struttura di un programma, in nessun caso il software è stato realmente disassemblato o modificato; ogni corrispondenza presente tra i documenti pubblicati e le istruzioni del software oggetto dell'analisi, è da ritenersi puramente casuale. Tutti i documenti vengono inviati in forma anonima ed automaticamente pubblicati, i diritti di tali opere appartengono esclusivamente al firmatario del documento (se presente), in nessun caso il gestore di questo sito, o del server su cui risiede, può essere ritenuto responsabile dei contenuti qui presenti, oltretutto il gestore del sito non è in grado di risalire all'identità del mittente dei documenti. Tutti i documenti ed i file di questo sito non presentano alcun tipo di garanzia, pertanto ne è sconsigliata a tutti la lettura o l'esecuzione, lo staff non si assume alcuna responsabilità per quanto riguarda l'uso improprio di tali documenti e/o file, è doveroso aggiungere che ogni riferimento a fatti cose o persone è da considerarsi PURAMENTE casuale. Tutti coloro che potrebbero ritenersi moralmente offesi dai contenuti di queste pagine, sono tenuti ad uscire immediatamente da questo sito.

Vogliamo inoltre ricordare che il Reverse Engineering è uno strumento tecnologico di grande potenza ed importanza, senza di esso non sarebbe possibile creare antivirus, scoprire funzioni malevole e non dichiarate all'interno di un programma di pubblico utilizzo. Non sarebbe possibile scoprire, in assenza di un sistema sicuro per il controllo dell'integrità, se il "tal" programma è realmente quello che l'utente ha scelto di installare ed eseguire, né sarebbe possibile continuare lo sviluppo di quei programmi (o l'utilizzo di quelle periferiche) ritenuti obsoleti e non più supportati dalle fonti ufficiali.