API Tracing)
As many trojan programs are processed, they gradually feel that the static/dynamic manual analysis process is largely repetitive. It takes half an hour to understand the features of the program. During manual analysis, you may miss a hidden key operation, resulting in incomplete removal. In fact, as long as the API call sequence and corresponding parameters are fully recorded when the trojan is actively installed, the workload of Trojan analysis and removal can be greatly reduced.
I have previously written a small tool that uses API hooking principles to record suspicious program operations on files, registries, services, and networks. The advantage of the API hooking method is that when createfile is called, the file name can be associated with the handle, and the file name can be obtained easily when writefile is called to operate on the handle, this is also true for handle operations such as hkey and socket. However, the disadvantages of this method are also obvious. First, you must write code for every API function that you are interested in. Second, you cannot hook all the API functions, due to the lack of complete API call sequence for reference, some small actions may be missed during log analysis.
Another idea is to use the debugging technology to set breakpoints in advance at the entrances of all introduced DLL functions, and obtain parameters through stack information during debugging. Both Ida pro and ollydbg can be used for dynamic debugging and provide script/plug-in functions. During my meeting in Beijing last week, I used the waking time to write a simple ollydbg plug-in. I only obtained eight function parameters from the call command using the ESP pointer, the eax and stack content returned by the function are not recorded, and the results are still satisfactory in the test of common (unshelled) programs. You only need to execute "Set breakpoint on every command" in the "Search for-> All intermodular CILS" window to set the breakpoint, and then run the "Fast trace" function of the plug-in. The log file snippets are as follows:
-------------------------------------------------------------------
004099ec: Call dword ptr ds: [<& kernel32.getmodulefilenamea>] (kernel32.getmodulefilenamea)
-------------------------------------------------------------------
ESP + 00 (0012f704): 00000000
ESP + 04 (0012f708): 0012f824 ""
ESP + 08 (0012f70c): 00000104 00000104 ???
ESP + 0C (0012f710): 0012fa6d ""
ESP + 10 (0012f714): 00000001 00000001 ???
ESP + 14 (0012f718): 00000000
ESP + 18 (0012f71c): 575c3a43 575c3a43 ???
ESP + 1C (0012f720): 4f444e49 4f444e49 ???
-------------------------------------------------------------------
00409a00: Call dword ptr ds: [<& kernel32.copyfilea>] (kernel32.copyfilea)
-------------------------------------------------------------------
ESP + 00 (0012f704): 0012f824 "E: \ trojan.exe"
ESP + 04 (0012f708): 0012f71c "C: \ windows \ system32 \ trojan.exe"
ESP + 08 (0012f70c): 00000000
ESP + 0C (0012f710): 0012fa6d ""
ESP + 10 (0012f714): 00000001 00000001 ???
ESP + 14 (0012f718): 00000000
ESP + 18 (0012f71c): 575c3a43 575c3a43 ???
ESP + 1C (0012f720): 4f444e49 4f444e49 ???
-------------------------------------------------------------------
00409a94: Call dword ptr ds: [<& advapi32.openscmanagera>] (advapi32.openscmanagera)
-------------------------------------------------------------------
ESP + 00 (0012f704): 00000000
ESP + 04 (0012f708): 00000000
ESP + 08 (0012f70c): 000f003f 000f003f ???
ESP + 0C (0012f710): 0012fa6d ""
ESP + 10 (0012f714): 00000001 00000001 ???
ESP + 14 (0012f718): 00000000
ESP + 18 (0012f71c): 575c3a43 575c3a43 ???
ESP + 1C (0012f720): 4f444e49 4f444e49 ???
-------------------------------------------------------------------
00409acf: Call dword ptr ds: [<& advapi32.createservicea>] (advapi32.createservicea)
-------------------------------------------------------------------
ESP + 00 (0012f6dc): 0014f9c0
F8 F9 14 00 98 Ba DC Fe 00 00 00 B4 F9 CC 53 ...... S
82 6C FC 42 BF 8C 55 14 00 44 14 F4 AB AB. l. B... u... d ......
AB EE Fe 00 00 00 00 00 00 00 ................
20 00 07 00 09 07 18 00 58 fa C3 77 ef cd AB 89... X... w ....
00 00 01 00 00 00 00 00 00 00 00 00 00 ................
00 00 00 00 00 00 00 05 00 00 00 00 00 00 00 ................
00 00 00 00 00 00 00 00 00 00 00 00 00 ................
06 00 00 00 0a 00 00 00 00 00 30 FB 14 00...
ESP + 04 (0012f6e0): 0042008c "Trojan"
ESP + 08 (0012f6e4): 004200c0 "back door for testing"
ESP + 0C (0012f6e8): 000f01ff 000f01ff ???
ESP + 10 (0012f6ec): 00000120 00000120 ???
ESP + 14 (0012f6f0): 00000002 00000002 ???
ESP + 18 (0012f6f4): 00000001 00000001 ???
ESP + 1C (0012f6f8): 0012f71c "C: \ windows \ system32 \ trojan.exe-start"
......
This simple and rough log is enough for me. To display parameter information in a more friendly way, you must have some data files to describe the calling method, return value type, number of parameters, and so on of each API function. For example:
Int loadlibrarya ([in] char * lplibfilename );
Int loadlibraryw ([in] wchar * lplibfilename );
Void * getprocaddress ([in] int hmodule, [in] char * lpprocname );
Int getmodulefilenamea ([in] int hmodule, [out] char * lpfilename, [in] int nsize );
Int getmodulefilenamew ([in] int hmodule, [out] wchar * lpfilename, [in] int nsize );
Compile a simple lexical parsing module to directly parse the. h file that comes with VC, which is easier for users. After parameter type resolution, the output information will look much better:
------------------------------------------------------
004099f2-> getmodulefilenamea (
Int hmodule: 0 (unsigned = 0/Hex = 0 ),
Char * lpfilename: [0012f824] = "",
Int nsize: 260 (unsigned = 260/Hex = 104 ),
13 <Results
Int hmodule: 0 (unsigned = 0/Hex = 0 ),
Char * lpfilename: [0012f824] = "E: \ trojan.exe" in stack of thread,
Int nsize: 260 (unsigned = 260/Hex = 104)
);
------------------------------------------------------
00409a06-> copyfilea (
Char * lpexistingfilename: [0012f824] = "E: \ trojan.exe" in stack of thread,
Char * lpnewfilename: [0012f71c] = "C: \ windows \ system32 \ trojan.exe" in stack of thread,
Int bfailifexists: 0 (unsigned = 0/Hex = 0 ),
1 <Results
Char * lpexistingfilename: [0012f824] = "",
Char * lpnewfilename: [0012f71c] = "",
Int bfailifexists: 0 (unsigned = 0/Hex = 0)
);
------------------------------------------------------
00409a9a-> openscmanagera (
Char * lpmachinename: [00000000] = (null ),
Char * lpdatabasename: [00000000] = (null ),
Int dwdesiredaccess: 983103 (unsigne= 983103/Hex = f003f ),
1374656 <Results
Char * lpmachinename: [00000000] = "",
Char * lpdatabasename: [00000000] = "",
Int dwdesiredaccess: 983103 (unsigne= 983103/Hex = f003f)
);
------------------------------------------------------
00409ad5-> createservicea (
Int hscmanager: 1374656 (unsigne= 1374656/Hex = 14f9c0 ),
Char * lpservicename: [0042008c] = "Trojan" in main image (. Data ),
Char * lpdisplayname: [004200c0] = "back door for testing" in main image (. Data ),
Int dwdesiredaccess: 983551 (unsigne= 983551/Hex = f01ff ),
Int dwservicetype: 288 (unsigned = 288/Hex = 120 ),
Int dwstarttype: 2 (unsigned = 2/Hex = 2 ),
Int dwerrorcontrol: 1 (unsigned = 1/Hex = 1 ),
Char * lpbinarypathname: [0012f71c] = "C: \ windows \ system32 \ trojan.exe-start" in stack of thread,
Char * lploadordergroup: [00000000] = (null ),
Int * lpdwtagid: 00000000,
Char * lpdependencies: [004201c4] = "" in main image (. Data ),
Char * lpservicestartname: [00000000] = (null ),
Char * lppassword: [00000000] = (null ),
1370392 <Results
Int hscmanager: 1374656 (unsigne= 1374656/Hex = 14f9c0 ),
Char * lpservicename: [0042008c] = "",
Char * lpdisplayname: [004200c0] = "",
Int dwdesiredaccess: 983551 (unsigne= 983551/Hex = f01ff ),
Int dwservicetype: 288 (unsigned = 288/Hex = 120 ),
Int dwstarttype: 2 (unsigned = 2/Hex = 2 ),
Int dwerrorcontrol: 1 (unsigned = 1/Hex = 1 ),
Char * lpbinarypathname: [0012f71c] = "",
Char * lploadordergroup: [00000000] = "",
Int * lpdwtagid: 00000000,
Char * lpdependencies: [004201c4] = "",
Char * lpservicestartname: [00000000] = "",
Char * lppassword: [00000000] = ""
);
......
Dumbug is an open-source API tracing tool, but it is designed to only trace the API calls defined in the trace file. To obtain the complete API call sequence through the original dumbug, the workload is no less than the API hooking method. In addition, for trojan programs, we do not need to record the API call sequence in the system link library such as kernel32.dll. Therefore, we should filter the information based on the EXE and DLL entry addresses and code segment length, minimize redundant information. In dumbug, you only need to add some code for the activatetraces () method of the tracer object, and make minor modifications elsewhere to output the above results.
The source code of Appendix 1-dumbug can be obtained from:
[Url] http://www.phenoelit.de/dumbug/dumbugvegasrelease.zip#/url]
Appendix 2-simple apitracing-plugin for ollydbg source code:
// Apitracing. c
# Define strict // avoids some type mismatches
# Include <windows. h>
# Include <stdio. h>
# Include <dir. h>
# Include "plugin. H"
# Define versionhi 1 // high plugin version
# Define versionlo 0 // low plugin version
# Define log_filename "traceapi. log" // log filename
Static hinstance hinst; // DLL instance
Static bool bfasttracing = true;
Static bool bstarttrace = false;
Int execute (char * Text, char * answer );
Bool winapi dllentrypoint (hinstance hi, DWORD reason, lpvoid reserved)
{
File * flog;
If (reason = dll_process_attach ){
Hinst = Hi; // mark plugin instance
Flog = fopen (log_filename, "W ");
If (flog ){
Fprintf (flog, "API tracing plugin v % I. % 02i, written by glacier_at_xfocus.org \ n ",
Versionhi, versionlo );
Fclose (flog );
}
}
Return 1; // report success
}
// Report plugin name and return version of plugin interface.
Extc int _ export cdecl odbg_plugindata (char shortname [32])
{
Strcpy (shortname, "API tracing"); // name of command line plugin
Return plugin_version;
}
Extc int _ export cdecl odbg_plugininit (INT ollydbgversion, hwnd HW, ulong * features)
{
// This plugin uses some newest features,
// Check that version of ollydbg is correct.
If (ollydbgversion <plugin_version)
Return-1;
Return 0;
}
Extc void _ export cdecl odbg_pluginmainloop (debug_event * debugevent ){
}
// Function adds items to main ollydbg menu (origin = pm_main ).
Extc int _ export cdecl odbg_pluginmenu (INT origin, char data [4096], void * item)
{
If (Origin! = Pm_main)
Return 0; // No pop-up menus in ollydbg's windows
Strcpy (data, "0 & fast trace, 1 & slow trace | 2 & about ");
Return 1;
}
// Es commands from main menu.
Extc void _ export cdecl odbg_pluginaction (INT origin, int action, void * item)
{
Char szline [max_path] = {0 };
If (Origin! = Pm_main)
Return;
Switch (Action ){
Case 0: // fast Tracing
Bfasttracing = true;
Bstarttrace = true;
Sendshortcut (pm_main, 0, wm_keydown, 0, 0, vk_f9 );
Break;
Case 1: // slow Tracing
Bfasttracing = false;
Bstarttrace = true;
Sendshortcut (pm_main, 0, wm_keydown, 0, 0, vk_f7 );
Break;
Case 2: // "about", displays plugin info
Sprintf (szline, "API tracing plugin v % I. % 02i ",
Versionhi, versionlo );
MessageBox (0, szline, "API tracing", mb_ OK | mb_iconinformation );
Break;
Default: break;
}
}
// User opens new or restarts current application.
Extc void _ export cdecl odbg_pluginreset (void)
{
Bstarttrace = false;
}
Extc int _ export cdecl odbg_pluginclose (void)
{
Return 0;
}
Extc void _ export cdecl odbg_plugindestroy (void)
{
}
// Record binary content
Void logbintofile (char * szfilename, const char * pbuf, int nsize)
{
File * flog;
Int I, J;
Unsigned const char * PTR = (unsigned const char *) pbuf;
Flog = fopen (szfilename, "A + ");
If (! Flog) return;
If (nsize = 0)
Nsize = strlen (pbuf );
For (I = 0; I <nsize; I = I + 0x10 ){
Fprintf (flog, "\ t ");
For (j = I; j <I + 0x10 & J <nsize; j ++)
Fprintf (flog, "% 02x", PTR [J]);
Fprintf (flog, "\ t ");
For (j = I; j <I + 0x10 & J <nsize; j ++ ){
If (ischaralpha (PTR [J]) | (PTR [J]> = 0x20 & PTR [J] <0x7f ))
Fprintf (flog, "% C", PTR [J]);
Else
Fprintf (flog, "% C ",'.');
}
Fprintf (flog, "\ n ");
}
Fclose (flog );
}
// Format the record log
Void logtofile (char * szfilename, char * szfmt ,...)
{
File * flog;
Char buff [1024];
Va_list Arglist;
Va_start (Arglist, szfmt );
_ Vsnprintf (buff, sizeof (buff), szfmt, Arglist );
Va_end (Arglist );
Flog = fopen (szfilename, "A + ");
If (! Flog) return;
Fprintf (flog, "% s", buff );
Fclose (flog );
}
// Check whether it is an ASCII string
Bool checkcharalpha (char * szline)
{
Int I = 0;
While (szline [I]) {
If (! Ischaralpha (szline [I]) & (szline [I] <0x20 | szline [I]> = 0x7f ))
Return false;
I ++;
}
Return true;
}
Extc int _ export cdecl odbg_paused (INT reason, t_reg * REG)
{
Char szsrcdec [1024] = {0 };
Char szline [1024] = {0 };
Unsigned long uesp = 0, uaddr = 0, utemp = 0;
Int nsize = 0, I = 0;
If (! Bstarttrace) return 0;
If (! Reg ){
ShellExecute (0, "open", "notepad.exe", log_filename, null, sw_show );
Return 0;
}
// Read the instruction at the breakpoint
Nsize = readcommand (reg-> ip, szline );
If (nsize> 0 ){
T_disasm disasm;
// Disassemble binary commands
Disasm (szline, nsize, reg-> ip, szsrcdec, & disasm, disasm_all, 0 );
If (strstr (disasm. result, "call") {// if it is a call command
Logtofile (log_filename, "\ n % s \ n ",
"------------------------------------------------------");
Logtofile (log_filename, "% 08x: % s (% s)", reg-> ip, disasm. Result, disasm. Comment );
Logtofile (log_filename, "\ n % s \ n ",
"------------------------------------------------------");
Uesp = reg-> r [4];
// Eight stack parameters read by ESP
Utemp = uesp;
For (I = 0; I <8; I ++ ){
Readmemory (& uaddr, utemp, sizeof (uaddr), mm_silent );
Logtofile (log_filename, "\ TESP + % 02x (% 08x): % 08x", I * 4, utemp, uaddr );
If (uaddr = 0) nsize = 0;
Else nsize = decodeascii (uaddr, szline, sizeof (szline)-1, dasc_ascii );
If (nsize> 0 & checkcharalpha (szline )){
Logtofile (log_filename, "\ t % s \ n", szline );
}
Else {
Memset (szline, 0, sizeof (szline ));
Nsize = readmemory (szline, uaddr, 128, mm_silent );
If (nsize> 0 ){
Logtofile (log_filename, "\ n ");
Logbintofile (log_filename, szline, nsize );
}
Else
Logtofile (log_filename, "\ n ");
}
Utemp + = 4;
}
}
// Continue execution
If (bfasttracing)
Sendshortcut (pm_main, 0, wm_keydown, 0, 0, vk_f9 );
Else {
If (strstr (disasm. result, ". 0 ")){
Go (0, reg-> ip, step_in, 1, 0 );
}
Else {
Go (0, reg-> ip, step_over, 1, 0 );
}
}
}
Return 0;
}