Exemplo n.º 1
0
void profile(struct emu_config *conf, struct connection *con, void *data, unsigned int size, unsigned int offset)
{
	struct emu *e = emu_new();
	struct emu_env *env = emu_env_new(e);
	env->profile = emu_profile_new();

//	struct emu_cpu *cpu = emu_cpu_get(e);
	struct emu_memory *mem = emu_memory_get(e);
	emu_cpu_reg32_set(emu_cpu_get(e), esp, 0x0012fe98);

	emu_memory_write_block(mem, CODE_OFFSET, data,  size);
	emu_cpu_eip_set(emu_cpu_get(e), CODE_OFFSET + offset);
	run(e, env);

	bool needemu = false;

	struct emu_profile_function *function;
	for( function = emu_profile_functions_first(env->profile->functions); !emu_profile_functions_istail(function); function = emu_profile_functions_next(function) )
	{
		if( strcmp("recv", function->fnname) == 0 )
		{
			g_message("Can not profile %s, emulating instead", function->fnname);
			needemu = true;
		}
	}


	if( needemu == true )
	{
		emulate(conf, con, data, size, offset);
	} else
	{
		GString *str = g_string_new(NULL);
		json_profile_debug(env->profile, str);
		//printf("%s", str->str);
		struct incident *i = incident_new("dionaea.module.emu.profile");
		incident_value_string_set(i, "profile", str);
		incident_value_con_set(i, "con", con);
		connection_ref(con);
		GAsyncQueue *aq = g_async_queue_ref(g_dionaea->threads->cmds);
		g_async_queue_push(aq, async_cmd_new(async_incident_report, i));
		g_async_queue_unref(aq);
		ev_async_send(g_dionaea->loop, &g_dionaea->threads->trigger);
	}

	emu_env_free(env);
	emu_free(e);
}
Exemplo n.º 2
0
/**
 * 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'
 *  
 * 
 * 
 * @param e         the emu to run
 * @param data      the data we run
 * @param datasize  the data size
 * @param eipoffset the offset for eip
 * @param steps     how many steps to try running
 * @param etas      the track and source tree - the substantial
 *                  information to run the breath first search
 * @param known_positions
 *                  already tested positions
 * @param stats_tested_positions_list
 *                  the result list
 * @param brute_force
 *                  be aggressive?
 * 
 * @return 
 */
int32_t     emu_shellcode_run_and_track(struct emu *e, 
										uint8_t *data, 
										uint16_t datasize, 
										uint16_t eipoffset,
										uint32_t steps,
//										struct emu_env_w32 *env, 
										struct emu_track_and_source *etas,
										struct emu_hashtable *known_positions,
										struct emu_list_root *stats_tested_positions_list,
										bool brute_force
									   )
{
	struct emu_cpu *cpu = emu_cpu_get(e);
	struct emu_memory *mem = emu_memory_get(e);


	struct emu_queue *eq = emu_queue_new();
	emu_queue_enqueue(eq, (void *)((uintptr_t)(uint32_t)eipoffset+STATIC_OFFSET));

//	struct emu_list_root *tested_positions = emu_list_create();

	struct emu_env *env = NULL;

	{ // mark all vertexes white

		struct emu_vertex *x;
		for ( x= emu_vertexes_first(etas->static_instr_graph->vertexes); !emu_vertexes_attail(x); x = emu_vertexes_next(x))
		{
			x->color = white;
		}

	}		 

	while ( !emu_queue_empty(eq) )
	{
		
		uint32_t current_offset = (uint32_t)(uintptr_t)emu_queue_dequeue(eq);

		/* init the cpu/memory 
		 * scooped to keep number of used varnames small 
		 */
        {
			logDebug(e, "running at offset %i %08x\n", current_offset, current_offset);

			emu_memory_clear(mem);
			if (env)
				emu_env_free(env);

			/* write the code to the offset */
			emu_memory_write_block(mem, STATIC_OFFSET, data, datasize);
			
			env = emu_env_new(e);

			/* set the registers to the initial values */
			int reg;
			for ( reg=0;reg<8;reg++ )
				emu_cpu_reg32_set(cpu,reg ,0x0);

			emu_cpu_reg32_set(cpu, esp, 0x00120000);
			emu_cpu_eip_set(cpu, current_offset);

			/* set the flags */
			emu_cpu_eflags_set(cpu,0x0);

			cpu->tracking = etas;
		}

		emu_tracking_info_clear(&etas->track);

		int j;
		for ( j=0;j<steps;j++ )
		{
//			emu_cpu_debug_print(cpu);
			uint32_t eipsave;
			eipsave = emu_cpu_eip_get(cpu);

			struct emu_env_hook *hook = NULL;

			hook = emu_env_w32_eip_check(env);


			if ( hook != NULL )
			{
				if ( hook->hook.win->fnhook == NULL )
					break;
			}
			else
			{

				int32_t ret = emu_cpu_parse(emu_cpu_get(e));
				if ( ret == -1 )
				{
					logDebug(e, "error at %s\n", cpu->instr_string);
					break;
				}

				ret = emu_cpu_step(emu_cpu_get(e));
				if ( ret == -1 )
				{
					logDebug(e, "error at %s (%s)\n", cpu->instr_string, strerror(emu_errno(e)));
					if (brute_force)
					{
						logDebug(e, "goto traversal\n");
						goto traversal;
					}
					else
						break;
				}

				if ( emu_track_instruction_check(e, etas) == -1 )
				{
traversal:
					logDebug(e, "failed instr %s\n", cpu->instr_string);
					logDebug(e, "tracking at eip %08x\n", eipsave);
					if ( 0 && cpu->instr.is_fpu )
					{

					}
					else
					{

						/* save the requirements of the failed instruction */
//						struct emu_tracking_info *instruction_needs_ti = emu_tracking_info_new();
//						emu_tracking_info_copy(&cpu->instr.cpu.track.need, instruction_needs_ti);

						struct emu_queue *bfs_queue = emu_queue_new();

						/*
						 * the current starting point is the first position used to bfs
						 * scooped to avoid varname collisions 
						 */
						{ 
							struct emu_tracking_info *eti = emu_tracking_info_new();
							emu_tracking_info_diff(&cpu->instr.track.need, &etas->track, eti);
							eti->eip = current_offset;
							emu_tracking_info_debug_print(eti);

							if( emu_hashtable_search(known_positions, (void *)(uintptr_t)(uint32_t)current_offset) != NULL)
							{
								logDebug(e, "Known %p %x\n", eti, eti->eip);
								emu_tracking_info_free(eti);
								emu_queue_free(bfs_queue);
								break;
							}

							emu_queue_enqueue(bfs_queue, eti);
						}
						while ( !emu_queue_empty(bfs_queue) )
						{
							logDebug(e, "loop %s:%i\n", __FILE__, __LINE__);

							struct emu_tracking_info *current_pos_ti_diff = (struct emu_tracking_info *)emu_queue_dequeue(bfs_queue);
							struct emu_hashtable_item *current_pos_ht = emu_hashtable_search(etas->static_instr_table, (void *)(uintptr_t)(uint32_t)current_pos_ti_diff->eip);
							if (current_pos_ht == NULL)
							{
								logDebug(e, "current_pos_ht is NULL?\n");
								exit(-1);
							}

							struct emu_vertex *current_pos_v = (struct emu_vertex *)current_pos_ht->value;
							struct emu_source_and_track_instr_info *current_pos_satii = (struct emu_source_and_track_instr_info *)current_pos_v->data;

							if( emu_hashtable_search(known_positions, (void *)(uintptr_t)(uint32_t)current_pos_satii->eip) != NULL )
							{
								logDebug(e, "Known Again %p %x\n", current_pos_satii, current_pos_satii->eip);
								current_pos_v->color = red;
								emu_tracking_info_free(current_pos_ti_diff);
								continue;
							}

							if (current_pos_v->color == red)
							{
								logDebug(e, "is red %p %x: %s\n", (uintptr_t)current_pos_v, current_pos_satii->eip, current_pos_satii->instrstring);
								emu_tracking_info_free(current_pos_ti_diff);
								continue;
							}

							logDebug(e, "marking red %p %x: %s \n", (uintptr_t)current_pos_v, current_pos_satii->eip, current_pos_satii->instrstring);
							current_pos_v->color = red;

							emu_hashtable_insert(known_positions, (void *)(uintptr_t)(uint32_t)current_pos_satii->eip, NULL);

							while ( !emu_tracking_info_covers(&current_pos_satii->track.init, current_pos_ti_diff) || brute_force )
							{
								logDebug(e, "loop %s:%i\n", __FILE__, __LINE__);

								if ( current_pos_v->backlinks == 0 )
								{
									break;
								}
								else
								if ( current_pos_v->backlinks > 1 )
								{ /* queue all to diffs to the bfs queue */
									struct emu_edge *ee;
									struct emu_vertex *ev;
									for ( ee = emu_edges_first(current_pos_v->backedges); !emu_edges_attail(ee); ee=emu_edges_next(ee) )
									{
										ev = ee->destination;
										/**
										 * ignore positions we've visited already 
										 * avoids dos for jz 0 
										 *  
										 * try the next position instead 
										 */
										if( ev->color == red )
											continue;

										struct emu_source_and_track_instr_info *next_pos_satii =  (struct emu_source_and_track_instr_info *)ev->data;
										

										

										logDebug(e, "EnqueueLoop %p %x %s\n", next_pos_satii, next_pos_satii->eip, next_pos_satii->instrstring);
										struct emu_tracking_info *eti = emu_tracking_info_new();
										emu_tracking_info_diff(current_pos_ti_diff, &current_pos_satii->track.init, eti);
										eti->eip = next_pos_satii->eip;
										emu_queue_enqueue(bfs_queue, eti);
									}
									/**
									 * 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
									 */
									break;
								}
								else
								if ( current_pos_v->backlinks == 1 )
								{ /* follow the single link */
									/**
									 * ignore loops	to self 
									 * avoids dos for "\xe3\xfe\xe8" 
									 * breaks the upper loop 
									 *  
									 */
									if( current_pos_v == emu_edges_first(current_pos_v->backedges)->destination )
										break;
									
									current_pos_v = emu_edges_first(current_pos_v->backedges)->destination;
									/**
									 * again, ignore already visited positions 
									 * breaks the upper loop 
									 */
									if( current_pos_v->color == red )
										break;

									current_pos_v->color = red;
									
									struct emu_source_and_track_instr_info *next_pos_satii =  (struct emu_source_and_track_instr_info *)current_pos_v->data;
									logDebug(e, "FollowSingle %p %i %x %s\n", next_pos_satii, current_pos_v->color, next_pos_satii->eip, next_pos_satii->instrstring);
									current_pos_satii = (struct emu_source_and_track_instr_info *)current_pos_v->data;
									emu_tracking_info_diff(current_pos_ti_diff, &current_pos_satii->track.init, current_pos_ti_diff);
								}
							}

							if ( emu_tracking_info_covers(&current_pos_satii->track.init, current_pos_ti_diff) || brute_force )
							{
								/**
								 * 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
								 */
								logDebug(e, "found position which satiesfies the requirements %i %08x\n", current_pos_satii->eip, current_pos_satii->eip);
								current_pos_ht = emu_hashtable_search(etas->static_instr_table, (void *)(uintptr_t)(uint32_t)current_pos_satii->eip);
								current_pos_v = (struct emu_vertex *)current_pos_ht->value;

								if(current_pos_satii->eip != current_offset )
								{
									logDebug(e, "marking white %p %x: %s \n", (uintptr_t)current_pos_v, current_pos_satii->eip, current_pos_satii->instrstring);
									current_pos_v->color = white;
								}
								emu_tracking_info_debug_print(&current_pos_satii->track.init);
								emu_queue_enqueue(eq, (void *)((uintptr_t)(uint32_t)current_pos_satii->eip));
							}
//discard:
							emu_tracking_info_free( current_pos_ti_diff);
						}
						emu_queue_free(bfs_queue);
					}
					/** 
					 * 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
                     */
					break;
				}else
				{
					logDebug(e, "%s\n", cpu->instr_string);
				}
			}
		}

		struct emu_stats *es = emu_stats_new();
		es->eip = current_offset;
		es->cpu.steps = j;
		struct emu_list_item *eli = emu_list_item_create();
		eli->data = es;
		logDebug(e, "INSERT %i %x steps %i\n", current_offset, current_offset, j);
		emu_list_insert_last(stats_tested_positions_list, eli);
	}

	emu_queue_free(eq);
	emu_env_free(env);

	/* sort all tested positions by the number of steps ascending */
	emu_list_qsort(stats_tested_positions_list, tested_positions_cmp);

	struct emu_list_item *eli = emu_list_first(stats_tested_positions_list);
	struct emu_stats *es = (struct emu_stats *)eli->data;
	uint32_t best_offset = es->eip;

	return best_offset - STATIC_OFFSET;
}
Exemplo n.º 3
0
void __cdecl main(void){
	
	e = emu_new();
	cpu = emu_cpu_get(e);
	mem = emu_memory_get(e);
	env = emu_env_new(e);
	
	//emu_log_level_set( emu_logging_get(e),  EMU_LOG_DEBUG);

	if ( env == 0 ){ printf("%s\n%s\n", emu_strerror(e), strerror(emu_errno(e))); exit(-1);}

	int i =  0;
	void* stack;
	int stacksz;

	//            0      1      2      3      4      5         6      7    
	int regs[] = {0,    0,      0,     0,  0x12fe00,0x12fff0  ,0,    0};
	//*regm[] = {"eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"};

	for (i=0;i<8;i++) cpu->reg[(emu_reg32)i] = regs[i];

	stacksz = regs[ebp] - regs[esp] + 500;
	stack = malloc(stacksz);
	memset(stack, 0, stacksz);
	
	//printf("writing initial stack space\n");
	emu_memory_write_block(mem, regs[esp] - 250, stack, stacksz);

	emu_env_w32_export_new_hook(env, "LoadLibraryA", new_user_hook_LoadLibraryA, NULL);

	/*	00436A32     B8 00000000    MOV EAX,0
		00436A37     40             INC EAX

		00436A3D     68 6C333200    PUSH 32336C
		00436A42     68 7368656C    PUSH 6C656873
		00436A47     54             PUSH ESP
		00436A48     68 771D807C    PUSH 7C801D77
		00436A4D     59             POP ECX
		00436A4E     FFD1           CALL ECX 

		686C333200687368656C5468771D807C59FFD1   */

	unsigned char shellcode[20] = {
		0x68, 0x6C, 0x33, 0x32, 0x00, 0x68, 0x73, 0x68, 0x65, 0x6C, 0x54, 0x68, 0x77, 0x1D, 0x80, 0x7C, 
		0x59, 0xFF, 0xD1, 0xCC
	};

	//write shellcode to memory
	emu_memory_write_block(mem, 0x401000, shellcode,  20);

	emu_cpu_eip_set(cpu, 0x401000);
	system("cls");

	int step=0;
	char* buf = (char*)malloc(100);

	while(1){
		
		struct emu_env_w32_dll_export *ex = NULL;
		ex = emu_env_w32_eip_check(env);

		if(ex != NULL){ 
			//eip was found to be the start address of some dll export
			if(ex->fnhook == NULL){ //if fnhook != 0 then handler was executed by library already
				printf("Unhooked call to api %s\n", ex->fnname); //can insert generic handler here
				break;
			}
		}
		else{
			
			emu_disasm_addr(cpu, cpu->eip, buf);
			printf("%x\t%s\n", cpu->eip, buf);

			if( emu_cpu_parse(cpu) == -1){
				printf("step %d  parse failed error: %s", step, emu_strerror(e));
				break;
			}
			
			if( emu_cpu_step(cpu) == -1){
				printf("step %d  step failed error: %s", step, emu_strerror(e));
				break;
			}
			step++;
		}
			
	}

	printf("Run complete step=%d eax is: %x\n\n", step, cpu->reg[eax]);
	getch();
	

}
Exemplo n.º 4
0
void emulate(struct emu_config *conf, struct connection *con, void *data, unsigned int size, unsigned int offset)
{
	struct emu_emulate_ctx *ctx = g_malloc0(sizeof(struct emu_emulate_ctx));
	ctx->config = conf;

	ctx->sockets = g_hash_table_new(g_int_hash, g_int_equal);
	ctx->processes = g_hash_table_new(g_int_hash, g_int_equal);
	ctx->files = g_hash_table_new(g_int_hash, g_int_equal);

	ctx->ctxcon = con;
	if( con )
		connection_ref(ctx->ctxcon);

	ctx->emu = emu_new();
	ctx->env = emu_env_new(ctx->emu);
	struct emu_env * env = ctx->env;
	struct emu *e = ctx->emu;
	struct emu_cpu *cpu = emu_cpu_get(ctx->emu);
	ctx->env->userdata = ctx;
	g_mutex_init(&ctx->mutex);
	ctx->serial = 67;

	emu_env_w32_load_dll(env->env.win,"ws2_32.dll");
	emu_ll_w32_export_hook(env, "accept", ll_win_hook_accept, NULL);
	emu_env_w32_export_hook(env, "bind", user_hook_bind, NULL);
	emu_env_w32_export_hook(env, "closesocket", user_hook_close, NULL);
	emu_env_w32_export_hook(env, "connect", user_hook_connect, NULL);

	emu_env_w32_export_hook(env, "listen", user_hook_listen, NULL);
	emu_ll_w32_export_hook(env, "recv", ll_win_hook_recv, NULL);
	emu_env_w32_export_hook(env, "send", user_hook_send, NULL);
	emu_env_w32_export_hook(env, "socket", user_hook_socket, NULL);
	emu_env_w32_export_hook(env, "WSASocketA", user_hook_WSASocket, NULL);
	emu_env_w32_export_hook(env, "CreateProcessA", user_hook_CreateProcess, NULL);
	emu_env_w32_export_hook(env, "WaitForSingleObject", user_hook_WaitForSingleObject, NULL);

	emu_env_w32_export_hook(env, "CreateFileA", user_hook_CreateFile, NULL);
	emu_env_w32_export_hook(env, "WriteFile", user_hook_WriteFile, NULL);
	emu_env_w32_export_hook(env, "CloseHandle", user_hook_CloseHandle, NULL);

	emu_env_w32_export_hook(env, "_lcreat", user_hook__lcreat, NULL);
	emu_env_w32_export_hook(env, "_lwrite", user_hook__lwrite, NULL);
	emu_env_w32_export_hook(env, "_lclose", user_hook__lclose, NULL);

//	emu_env_linux_syscall_hook(env, "exit", user_hook_exit, NULL);
//	emu_env_linux_syscall_hook(env, "socket", user_hook_socket, NULL);
//	emu_env_linux_syscall_hook(env, "bind", user_hook_bind, NULL);
//	emu_env_linux_syscall_hook(env, "listen", user_hook_listen, NULL);
//	emu_env_linux_syscall_hook(env, "accept", user_hook_accept, NULL);

#define CODE_OFFSET 0x417000

	int j;
	for( j=0; j<8; j++ )
		emu_cpu_reg32_set(cpu,j , 0);

// set flags
	emu_cpu_eflags_set(cpu, 0);

// write code to offset
	emu_memory_write_block(emu_memory_get(ctx->emu), CODE_OFFSET, data,  size);

// set eip to code
	emu_cpu_eip_set(emu_cpu_get(e), CODE_OFFSET + offset);
	emu_cpu_reg32_set(emu_cpu_get(e), esp, 0x0012fe98);
	emulate_thread(NULL, ctx);
}