File: main.cpp

package info (click to toggle)
unicorn-engine 2.1.4-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 23,912 kB
  • sloc: ansic: 379,830; python: 9,213; sh: 9,011; java: 8,609; ruby: 4,241; pascal: 1,805; haskell: 1,379; xml: 490; cs: 424; makefile: 348; cpp: 298; asm: 64
file content (459 lines) | stat: -rw-r--r-- 13,047 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459

/* 
	stdcall unicorn engine shim layer for use with VB6 or C#
	code ripped from unicorn_dynload.c 
	
	Contributed by: FireEye FLARE team
	Author:         David Zimmer <david.zimmer@fireeye.com>, <dzzie@yahoo.com>
	License:        Apache 2.0

	Disassembler support can be optionally compiled in using:
	   libdasm (c) 2004 - 2006  jt / nologin.org

    this project has been built with vs2008

    precompiled binaries with disasm support available here:
       https://github.com/dzzie/libs/tree/master/unicorn_emu

*/

#include <io.h>
#include <windows.h>

#ifdef _WIN64
#error vb6 is 32bit only
#endif

#include <unicorn/unicorn.h>
#pragma comment(lib, "unicorn.lib")

//if you compile with VS2008 you will need to add stdint.h and inttypes.h to your compiler include directory
//you can find examples here: https://github.com/dzzie/VS_LIBEMU/tree/master/libemu/include

//if you want to include disassembler support:
//  1) install libdasm in your compilers include directory 
//  2) add libdasm.h/.c to the project (drag and drop into VS project explorer),
//  3) remove the comment from the define below. 
//The vb code detects the changes at runtime.
//#define INCLUDE_DISASM

#ifdef INCLUDE_DISASM
#include <libdasm/libdasm.h>
#endif


#include "msvbvm60.tlh" //so we can use the vb6 collection object

#define EXPORT comment(linker, "/EXPORT:"__FUNCTION__"="__FUNCDNAME__)


enum hookCatagory{hc_code = 0, hc_block = 1, hc_inst = 2, hc_int = 3, hc_mem = 4, hc_memInvalid = 5};

//tracing UC_HOOK_CODE & UC_HOOK_BLOCK 
typedef void (__stdcall *vb_cb_hookcode_t)   (uc_engine *uc,  uint64_t address,  uint32_t size,    void *user_data); 
vb_cb_hookcode_t vbHookcode = 0;
vb_cb_hookcode_t vbHookBlock = 0;

//hooking memory UC_MEM_READ/WRITE/FETCH 
typedef void (__stdcall *vb_cb_hookmem_t)    (uc_engine *uc,  uc_mem_type type,  uint64_t address, int size,int64_t value, void *user_data);
vb_cb_hookmem_t vbHookMem = 0;

//invalid memory access  UC_MEM_*_UNMAPPED and UC_MEM_*PROT events 
typedef bool (__stdcall *vb_cb_eventmem_t)   (uc_engine *uc,  uc_mem_type type,  uint64_t address, int size, int64_t value, void *user_data);   
vb_cb_eventmem_t vbInvalidMem = 0;

//tracing interrupts for uc_hook_intr() 
typedef void (__stdcall *vb_cb_hookintr_t)   (uc_engine *uc,  uint32_t intno,    void *user_data); 
vb_cb_hookintr_t vbHookInt = 0;

/*
typedef uint32_t (__stdcall *uc_cb_insn_in_t)(uc_engine *uc,  uint32_t port,     int size,         void *user_data);                                      tracing IN instruction of X86
typedef void (__stdcall *uc_cb_insn_out_t)   (uc_engine *uc,  uint32_t port,     int size,         uint32_t value,  void *user_data);                     tracing OUT instruction of X86
*/

//------------------ [ call back proxies ] -------------------------
static void c_hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user_data)
{
	if(vbHookcode==0) return;
	vbHookcode(uc,address,size,user_data);
}

static void c_hook_mem(uc_engine *uc, uc_mem_type type,uint64_t address, int size, int64_t value, void *user_data)
{
	if(vbHookMem==0) return;
	vbHookMem(uc,type,address,size,value,user_data);
}

static bool c_hook_mem_invalid(uc_engine *uc, uc_mem_type type, uint64_t address, int size, int64_t value, void *user_data)
{
	if(vbInvalidMem==0) return false;
	return vbInvalidMem(uc,type,address,size,value,user_data);
}


static void c_hook_block(uc_engine *uc, uint64_t address, uint32_t size, void *user_data)
{
	if(vbHookBlock==0) return;
	vbHookBlock(uc,address,size,user_data);
}

static void c_hook_intr(uc_engine *uc, uint32_t intno, void *user_data)
{
	if(vbHookInt==0) return;
	vbHookInt(uc,intno,user_data);
}


/*
static uint32_t hook_in(uc_engine *uc, uint32_t port, int size, void *user_data)
{
}

static void hook_out(uc_engine *uc, uint32_t port, int size, uint32_t value, void *user_data)
{
}
*/

//-------------------------------------------------------------

//uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback, void *user_data, uint64_t begin, uint64_t end, ...);
//we need to use a C stub cdecl callback then proxy to the stdcall vb one..
//we could get cute with an asm thunk in vb but not worth complexity there are only a couple of them to support..
//cdecl callback to vb stdcall callback for tracing
uc_err __stdcall ucs_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback, void *user_data, uint64_t begin, uint64_t end, int catagory, int instr_id){
#pragma EXPORT

	if(catagory == hc_code){
		if(vbHookcode == 0){
			if((int)callback==0) return UC_ERR_FETCH_UNMAPPED;
			vbHookcode = (vb_cb_hookcode_t)callback;
		}
		return uc_hook_add(uc,hh,type,c_hook_code,user_data,begin,end);
	}

	if(catagory == hc_block){
		if(vbHookBlock == 0){
			if((int)callback==0) return UC_ERR_FETCH_UNMAPPED;
			vbHookBlock = (vb_cb_hookcode_t)callback;
		}
		return uc_hook_add(uc,hh,type,c_hook_block,user_data,begin,end);
	}

	if(catagory == hc_mem){ //then it is some combination of memory access hook flags..
		if(vbHookMem == 0){
			if((int)callback==0) return UC_ERR_FETCH_UNMAPPED;
			vbHookMem = (vb_cb_hookmem_t)callback;
		}
		return uc_hook_add(uc,hh,type,c_hook_mem,user_data,begin,end);
	}

	if(catagory == hc_memInvalid){ //then it is some combination of invalid memory access hook flags..
		if(vbInvalidMem == 0){
			if((int)callback==0) return UC_ERR_FETCH_UNMAPPED;
			vbInvalidMem = (vb_cb_eventmem_t)callback;
		}
		return uc_hook_add(uc,hh,type,c_hook_mem_invalid,user_data,begin,end);
	}

	if(catagory == hc_int){
		if(vbHookInt == 0){
			if((int)callback==0) return UC_ERR_FETCH_UNMAPPED;
			vbHookInt = (vb_cb_hookintr_t)callback;
		}
		return uc_hook_add(uc,hh,UC_HOOK_INTR,c_hook_intr,user_data,begin,end);
	}

	return UC_ERR_ARG;
}

unsigned int __stdcall ucs_dynload(char *path){
#pragma EXPORT
    /*#ifdef DYNLOAD
		return uc_dyn_load(path, 0);
	#else*/
		return 1;
	//#endif	
}

unsigned int __stdcall ucs_version(unsigned int *major, unsigned int *minor){
#pragma EXPORT
    return uc_version(major, minor);
}

bool __stdcall ucs_arch_supported(uc_arch arch){
#pragma EXPORT
    return uc_arch_supported(arch);
}

uc_err __stdcall ucs_open(uc_arch arch, uc_mode mode, uc_engine **uc){
#pragma EXPORT
    return uc_open(arch, mode, uc);
}

uc_err __stdcall ucs_close(uc_engine *uc){
#pragma EXPORT
    return uc_close(uc);
}

uc_err __stdcall ucs_query(uc_engine *uc, uc_query_type type, size_t *result){
#pragma EXPORT
    return uc_query(uc, type, result);
}

uc_err __stdcall ucs_errno(uc_engine *uc){
#pragma EXPORT
    return uc_errno(uc);
}

const char *__stdcall ucs_strerror(uc_err code){
#pragma EXPORT
    return uc_strerror(code);
}

uc_err __stdcall ucs_reg_write(uc_engine *uc, int regid, const void *value){
#pragma EXPORT
    return uc_reg_write(uc, regid, value);
}

uc_err __stdcall ucs_reg_read(uc_engine *uc, int regid, void *value){
#pragma EXPORT
    return uc_reg_read(uc, regid, value);
}

uc_err __stdcall ucs_reg_write_batch(uc_engine *uc, int *regs, void *const *vals, int count){
#pragma EXPORT
    return uc_reg_write_batch(uc, regs, vals, count);
}

uc_err __stdcall ucs_reg_read_batch(uc_engine *uc, int *regs, void **vals, int count){
#pragma EXPORT
    return uc_reg_read_batch(uc, regs, vals, count);
}

uc_err __stdcall ucs_mem_write(uc_engine *uc, uint64_t address, const void *bytes, uint64_t size){
#pragma EXPORT
    return uc_mem_write(uc, address, bytes, size);
}

uc_err __stdcall ucs_mem_read(uc_engine *uc, uint64_t address, void *bytes, uint64_t size){
#pragma EXPORT
    return uc_mem_read(uc, address, bytes, size);
}

uc_err __stdcall ucs_emu_start(uc_engine *uc, uint64_t begin, uint64_t until, uint64_t timeout, size_t count){
#pragma EXPORT
    return uc_emu_start(uc, begin, until, timeout, count);
}

uc_err __stdcall ucs_emu_stop(uc_engine *uc){
#pragma EXPORT
    return uc_emu_stop(uc);
}

uc_err __stdcall ucs_hook_del(uc_engine *uc, uc_hook hh){
#pragma EXPORT
    return uc_hook_del(uc, hh);
}

uc_err __stdcall ucs_mem_map(uc_engine *uc, uint64_t address, uint64_t size, uint32_t perms){
#pragma EXPORT
    return uc_mem_map(uc, address, size, perms);
}

//requires link against v1.0
uc_err __stdcall ucs_mem_map_ptr(uc_engine *uc, uint64_t address, uint64_t size, uint32_t perms, void *ptr){
#pragma EXPORT
    return uc_mem_map_ptr(uc, address, size, perms, ptr);
}


uc_err __stdcall ucs_mem_unmap(uc_engine *uc, uint64_t address, uint64_t size){
#pragma EXPORT
    return uc_mem_unmap(uc, address, size);
}

uc_err __stdcall ucs_mem_protect(uc_engine *uc, uint64_t address, uint64_t size, uint32_t perms){
#pragma EXPORT
    return uc_mem_protect(uc, address, size, perms);
}

uc_err __stdcall ucs_mem_regions(uc_engine *uc, uc_mem_region **regions, uint32_t *count){
#pragma EXPORT
    return uc_mem_regions(uc, regions, count);
}

uc_err __stdcall ucs_context_alloc(uc_engine *uc, uc_context **context){
#pragma EXPORT
    return uc_context_alloc(uc, context);
}

uc_err __stdcall ucs_free(void *mem){
#pragma EXPORT
    return uc_free(mem);
}

uc_err __stdcall ucs_context_save(uc_engine *uc, uc_context *context){
#pragma EXPORT
    return uc_context_save(uc, context);
}

uc_err __stdcall ucs_context_restore(uc_engine *uc, uc_context *context){
#pragma EXPORT
    return uc_context_restore(uc, context);
}

/*
char* asprintf(char* format, ...){
	
	char *ret = 0;
	
	if(!format) return 0;

	va_list args; 
	va_start(args,format); 
	int size = _vscprintf(format, args); 
	
	if(size > 0){
		size++; //for null
		ret = (char*)malloc(size+2);
		if(ret) _vsnprintf(ret, size, format, args);
	}

	va_end(args);
	return ret;
}*/

#ifdef INCLUDE_DISASM
int __stdcall disasm_addr(uc_engine *uc, uint32_t va, char *str, int bufLen){
#pragma EXPORT
	uint32_t instr_len = 0;
	int readLen = 15;
    uint8_t data[32];
	INSTRUCTION inst;

	if(bufLen < 100) return -1;

	//longest x86 instruction is 15 bytes, what if at the tail end of an allocation? try to read as much as we can..
	while(uc_mem_read(uc,va,data,readLen) != 0){
		readLen--;
		if(readLen == 0) return -2;
	}
  
	instr_len = get_instruction(&inst, data, MODE_32);
	if( instr_len == 0 ) return -3;

	get_instruction_string(&inst, FORMAT_INTEL, va, str, bufLen);

	/* 
	if(inst.type == INSTRUCTION_TYPE_JMP || inst.type == INSTRUCTION_TYPE_JMPC){
		if(inst.op1.type == OPERAND_TYPE_IMMEDIATE){
			if(strlen(str) + 6 < bufLen){
				if(getJmpTarget(str) < va){
					strcat(str,"   ^^");  
				}else{
					strcat(str,"  vv");
				}
			}
		}
	}*/

	return instr_len;
}
#endif


//maps and write in one shot, auto handles alignment..
uc_err __stdcall mem_write_block(uc_engine *uc, uint64_t address, void* data, uint64_t size, uint32_t perm){
#pragma EXPORT

	uc_err x;
	uint64_t base = address;
  uint64_t sz = size;

	while(base % 0x1000 !=0){
		base--;
		if(base==0) break;
	}
	
	sz += address-base; //if data starts mid block, we need to alloc more than just size..
	while(sz % 0x1000 !=0){
		sz++;
	}

	x = uc_mem_map(uc, base, sz, perm);
	if(x) return x;

	x = uc_mem_write(uc, address, (void*)data, size);
	if(x) return x;
	return UC_ERR_OK;
}

void addStr(_CollectionPtr p , char* str){
	_variant_t vv;
	vv.SetString(str);
	p->Add( &vv.GetVARIANT() );
}

uc_err __stdcall get_memMap(uc_engine *uc, _CollectionPtr *pColl){
#pragma EXPORT

   uc_mem_region *regions;
   uint32_t count;
   char tmp[200]; //max 46 chars used

   uc_err err = uc_mem_regions(uc, &regions, &count);
   
   if (err != UC_ERR_OK) return err;

   for (uint32_t i = 0; i < count; i++) {
     sprintf(tmp,"&h%llx,&h%llx,&h%x", regions[i].begin, regions[i].end, regions[i].perms);
	 addStr(*pColl,tmp);
   }

   //free(regions); //https://github.com/unicorn-engine/unicorn/pull/373#issuecomment-271187118
   
   uc_free((void*)regions);
   return err;

}

enum op{
	op_add = 0,
	op_sub = 1,
	op_div = 2,
	op_mul = 3,
	op_mod = 4,
	op_xor = 5,
	op_and = 6,
	op_or  = 7,
	op_rsh = 8,
	op_lsh = 9,
	op_gt  = 10,
	op_lt  = 11,
	op_gteq = 12,
	op_lteq = 13
};

unsigned int __stdcall ULong(unsigned int v1, unsigned int v2, int operation){
#pragma EXPORT

	switch(operation){
		case op_add: return v1 + v2;
		case op_sub: return v1 - v2;
		case op_div: return v1 / v2;
		case op_mul: return v1 * v2;
		case op_mod: return v1 % v2;
		case op_xor: return v1 ^ v2;
		case op_and: return v1 & v2;
		case op_or:  return v1 | v2;
		case op_rsh: return v1 >> v2;
		case op_lsh: return v1 << v2;
		case op_gt: return (v1 > v2 ? 1 : 0);
		case op_lt: return (v1 < v2 ? 1 : 0);
		case op_gteq: return (v1 >= v2 ? 1 : 0);
		case op_lteq: return (v1 <= v2 ? 1 : 0);
	}

	return -1;

}