emu_shellcode.c File Reference

#include "../config.h"
#include "emu/emu_shellcode.h"
#include "emu/emu.h"
#include "emu/emu_memory.h"
#include "emu/emu_cpu.h"
#include "emu/emu_cpu_data.h"
#include "emu/emu_track.h"
#include "emu/emu_source.h"
#include "emu/emu_getpc.h"
#include "emu/environment/emu_env.h"
#include "emu/environment/win32/emu_env_w32.h"
#include "emu/environment/win32/emu_env_w32_dll_export.h"
#include "emu/emu_hashtable.h"
#include "emu/emu_graph.h"
#include "emu/emu_list.h"
#include "emu/emu_queue.h"
#include "emu/emu_log.h"
Include dependency graph for emu_shellcode.c:

Defines

#define STATIC_OFFSET   0x00471000
#define EMU_SHELLCODE_TEST_MAX_STEPS   128

Enumerations

enum  { EMU_SCTEST_SUSPECT_GETPC, EMU_SCTEST_SUSPECT_MOVFS }

Functions

int tested_positions_cmp (struct emu_list_item *a, struct emu_list_item *b)
int32_t emu_shellcode_run_and_track (struct emu *e, uint8_t *data, uint16_t datasize, uint16_t eipoffset, uint32_t steps, struct emu_track_and_source *etas, struct emu_hashtable *known_positions, struct emu_list_root *stats_tested_positions_list, bool brute_force)
int32_t emu_shellcode_test (struct emu *e, uint8_t *data, uint16_t size)
struct emu_statsemu_stats_new (void)
void emu_stats_free (struct emu_stats *es)

Variables

enum { ... }  emu_shellcode_suspect

Define Documentation

#define EMU_SHELLCODE_TEST_MAX_STEPS   128
#define STATIC_OFFSET   0x00471000

Enumeration Type Documentation

anonymous enum
Enumerator:
EMU_SCTEST_SUSPECT_GETPC 
EMU_SCTEST_SUSPECT_MOVFS 

Function Documentation

int32_t emu_shellcode_run_and_track ( struct emu e,
uint8_t *  data,
uint16_t  datasize,
uint16_t  eipoffset,
uint32_t  steps,
struct emu_track_and_source etas,
struct emu_hashtable known_positions,
struct emu_list_root *  stats_tested_positions_list,
bool  brute_force 
)

This function takes the emu, the offset and tries to run steps iterations. If it fails due to uninitialized registers/eflags it will try to use the information passed by etas to traverse the instruction tree and find an instruction path in the tree which satisfies the initialization requirements.

To avoid testing the same positions over and over, the already-tested positions are held in the known_positions hashtable.

The result is returned in the tested_positions_list.

The function is called for every GetPC candidate in the suspected shellcode, therefore the known_positions prevent testing the same locations for different starting points in the data too.

It is the vital part of libemu's shellcode detection, hard to understand, hard to improve and hard to fix.

Messing this function up, destroys libemu's shellcode detection.

The function is a mess, given the complexity of the loops it is too long and the variable names do not provide any help.

The bruteforce flag is useful, as it allows bfs even if some instructions initializations are not set properly, but you'll definitely miss its impact on the behaviour when making a guess why something does not work.

short explanation of the logic:

the first starting point is our offset

while we have starting points: run the shellcode: error? no! continue yes! use the current starting eip as starting point to bfs look for instructions which satisfy the requirements OR brutefore queue these new instructions as starting points

History has proven the the function to be susceptible to denial of service attacks, running the system out of memory or cycles. So, if you experience a 'problem', this is the first place to look at, and the last one you want to look at, if you want to cause a 'problem', same rules apply.

This comment was written when patching one of these dos problems The known_positions arg has been unused for the time before, seems like there was a good idea when writing the function initially, but this good idea was abandoned once 'it worked'

Parameters:
e the emu to run
data the data we run
datasize the data size
eipoffset the offset for eip
steps how many steps to try running
etas the track and source tree - the substantial information to run the breath first search
known_positions already tested positions
stats_tested_positions_list the result list
brute_force be aggressive?
Returns:

ignore positions we've visited already avoids dos for jz 0

try the next position instead

the new possible positions and requirements got queued into the bfs queue, we break here, so the new queued positions can try to work it out

ignore loops to self avoids dos for "\xe3\xfe\xe8" breaks the upper loop

again, ignore already visited positions breaks the upper loop

we have a new starting point, this starting point may fail too - if further backwards traversal is required therefore we mark it white, so it can be processed again

the shellcode did not run correctly as he was missing instructions initializing required registers we did what we could do in the prev lines of code to find better offsets to start from the working offsets got queued into the main queue, so we break here to give them a chance

References emu_vertex::color, emu_stats::cpu, emu_list_item::data, emu_vertex::data, emu_edge::destination, emu_stats::eip, emu_source_and_track_instr_info::eip, emu_tracking_info::eip, emu_cpu_eflags_set(), emu_cpu_eip_get(), emu_cpu_eip_set(), emu_cpu_get(), emu_cpu_parse(), emu_cpu_reg32_set(), emu_cpu_step(), emu_env_w32_eip_check(), emu_errno(), emu_hashtable_insert(), emu_hashtable_search(), emu_list_item_create(), emu_memory_clear(), emu_memory_get(), emu_memory_write_block(), emu_queue_dequeue(), emu_queue_empty(), emu_queue_enqueue(), emu_queue_free(), emu_queue_new(), emu_stats_new(), emu_track_instruction_check(), emu_tracking_info_clear(), emu_tracking_info_covers(), emu_tracking_info_debug_print(), emu_tracking_info_diff(), emu_tracking_info_free(), emu_tracking_info_new(), esp, emu_cpu::instr, emu_cpu::instr_string, emu_source_and_track_instr_info::instrstring, emu_instruction::is_fpu, logDebug, emu_instruction::need, red, emu_track_and_source::static_instr_graph, emu_track_and_source::static_instr_table, STATIC_OFFSET, emu_stats::steps, tested_positions_cmp(), emu_instruction::track, emu_track_and_source::track, emu_cpu::tracking, emu_hashtable_item::value, emu_graph::vertexes, and white.

Referenced by emu_shellcode_test().

Here is the call graph for this function:

int32_t emu_shellcode_test ( struct emu e,
uint8_t *  data,
uint16_t  size 
)
void emu_stats_free ( struct emu_stats es  ) 

Referenced by emu_shellcode_test().

struct emu_stats* emu_stats_new ( void   )  [read]
int tested_positions_cmp ( struct emu_list_item a,
struct emu_list_item b 
)

Variable Documentation

enum { ... } emu_shellcode_suspect

Generated on Sun Jan 9 16:49:20 2011 for libemu by  doxygen 1.6.1