-
Notifications
You must be signed in to change notification settings - Fork 1
/
vm.h
330 lines (295 loc) · 7.95 KB
/
vm.h
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
//vm.h
/***
* Author: GeNi
* Date: Mars 2011
***/
#ifndef _VM_HEADER //Include once
#define _VM_HEADER
#ifdef Debug
#define CAN_DUMP
// #define VM_HEAP_TRACE
#define VM_DEBUG
// #define VM_DEBUG_STACK
#endif
#ifdef Library
//Nothing special to do
#else
#define CAN_COMPILE
#define HAS_CORE
#endif
#include <windows.h>
#include <stdio.h>
#define GENI_VM_VERSION 0x0101
#define DEFAULT_STACK_SIZE 64
#define DEFAULT_CALLSTACK_SIZE 64
#define MAX_REGISTER 32
#define DEFAULT_MEMORY_SIZE 64
#define CODE_CHUNK_SIZE 10
#define UNDEF32 OS_DWORD, OK_CONSTANT, OM_NORMAL, 0
#define CST32( num ) OS_DWORD, OK_CONSTANT, OM_NORMAL, num
#define REG32( num ) OS_DWORD, OK_REGISTER, OM_NORMAL, num
#define REG32PTR( num ) OS_DWORD, OK_REGISTER, OM_POINTER, num
#define REG32HPTR( num ) OS_DWORD, OK_REGISTER, OM_HOST_POINTER, num
#define REG32MODE( num, mode ) OS_DWORD, OK_REGISTER, mode, num
#define VMM32( num ) OS_DWORD, OK_VM_MEMORY, OM_NORMAL, num
#define VMM32PTR( num ) OS_DWORD, OK_VM_MEMORY, OM_POINTER, num
#define VMM32HPTR( num ) OS_DWORD, OK_VM_MEMORY, OM_HOST_POINTER, num
#define VMM32MODE( num, mode ) OS_DWORD, OK_VM_MEMORY, mode, num
#define HSTM32( num ) OS_DWORD, OK_HOST_MEMORY, OM_NORMAL, num
#define HSTM32PTR( num ) OS_DWORD, OK_HOST_MEMORY, OM_POINTER, num
#define HSTM32MODE( num, mode ) OS_DWORD, OK_HOST_MEMORY, mode, num
//~ typedef unsigned char BOOL;
#ifndef BYTE
typedef unsigned char BYTE;
#endif
#ifndef WORD
typedef unsigned short WORD;
#endif
#ifndef DWORD
typedef unsigned long DWORD;
#endif
typedef enum{
OC_MOV = 0,
OC_ADD,
OC_SUB,
OC_DIV,
OC_MUL,
OC_AND,
OC_OR,
OC_XOR,
OC_NOT,
OC_JMP,
OC_PUSH,
OC_POP,
OC_HCALL,
OC_CALL,
OC_RET,
OC_CMP,
OC_JZ,
OC_JNZ,
OC_JG,
OC_JL,
OC_JGE,
OC_JLE,
OC_VM2H,
OC_H2VM,
OC_PRINTL, // Output a data with a linefeed (printf("%s\n",)
OC_PRINT,
OC_STOP,
OC_MOVZB,
OC_MOVZW,
OC_SHL,
OC_SHR,
OC_NOP,
OC_MKCB, // CREATE A CALLBACK : ip, stack-size to copy from HOST to VM STACK
OC_RMCB, // DESTROY A CALLBACK: ip, not-used
OC_DUMP, // DUMP FROM left for "right" count values
OC_DEBUGBREAK,
OC_SPRINTF,
OC_NEG,
OC_API,
OC_HJUMP,
//OC_FINDDW, // Find the dword matching leftop.dword from rightop (incrementing rightop value by 4), returning rightop modified.
//OC_REPZ, // repz r4, 1; leftop = counter, rightop = instruction count (after current IP) ??? not finished to be digged !
//~ OC_GETBC, // GetBytecode function for the given ID
//~ OC_SETBC, // Set Bytecode function for the given ID
//~ OC_BP, // breakpoint
MAX_OPCODES // MUST be the last entry!
} OPCODES;
typedef enum{
OK_CONSTANT = 0,
OK_REGISTER,
OK_VM_MEMORY,
OK_HOST_MEMORY
} OPERAND_KIND;
typedef enum{ // This is something like a segment in traditional assembly.
OM_NORMAL = 0, // constant
OM_REG_POINTER, // register [ value ]
OM_VM_POINTER, // VM pointer
OM_HOST_POINTER // Host pointer
// Code pointer
// Stack pointer
} OPERAND_MODE;
typedef enum{
OS_BYTE = 1,
OS_WORD = 2,
OS_DWORD = 4
} OPERAND_SIZE, OPCODE_SIZE;
typedef struct _GENI_OPERAND{
OPERAND_SIZE size; //Currently not used, intend to be Byte, Word, Dword (, String ...) : more a datatype indicator
OPERAND_KIND type;
OPERAND_MODE mode;
union{ //value
BYTE byte;
WORD word;
DWORD dword;
} ;
} GENI_OPERAND;
typedef struct _GENI_OPCODE{
OPCODE_SIZE size; //8, 16, 24, 32 bits
OPCODES instruction; //OPCODES
GENI_OPERAND leftop;
GENI_OPERAND rightop;
} GENI_OPCODE;
typedef struct _GENI_CODE{
DWORD size;
DWORD ip;
BYTE stop;
GENI_OPCODE* opcodes;
//~ GENI_CODE* next;
} GENI_CODE;
typedef struct _GENI_MEMORY{
DWORD size;
DWORD storedbytes;
BYTE* ptr;
} GENI_MEMORY;
typedef struct _GENI_STACK{
DWORD size;
DWORD sp;
DWORD* ptr;
} GENI_STACK;
typedef struct _GENI_FLAGS{ //Like assembly processor flags, they are indicator of the last operation.
BOOL zero;
BOOL greater;
BOOL lower;
BOOL debug;
BOOL critical;
} GENI_FLAGS;
typedef struct _GENI_VM_INSTRUCTIONDEF{
#ifdef CAN_COMPILE
char* mnemonic;
#endif
DWORD/* fnHandler* */ handler;
} GENI_VM_INSTRUCTIONDEF;
//~ typedef struct _GENI_VM_INSTRUCTIONSET{
//~ GENI_VM_INSTRUCTIONDEF set[ 256 ];
//~ } GENI_VM_INSTRUCTIONSET;
typedef struct _GENI_REGISTER{
DWORD r[ MAX_REGISTER ];
} GENI_REGISTER;
typedef struct _GENI_CALLBACK{
DWORD host_address;
DWORD vm_ip;
DWORD arg_count;
DWORD vmptr;
DWORD* host_stack;
DWORD return_value;
} GENI_CALLBACK;
typedef struct _GENI_CALLBACKS{
DWORD count;
GENI_CALLBACK* items;
} GENI_CALLBACKS;
typedef DWORD (fnAPIHandler) (DWORD* , DWORD );
typedef struct _GENI_API{
DWORD id;
char* name;
fnAPIHandler* handler;
} GENI_API;
typedef struct _GENI_APIS{
DWORD count;
GENI_API* items;
} GENI_APIS;
typedef struct _GENI_VM{
GENI_CODE code;
GENI_MEMORY memory;
GENI_REGISTER registers;
GENI_STACK stack;
GENI_FLAGS flags;
GENI_VM_INSTRUCTIONDEF opcodeset[256];
GENI_STACK callstack;
GENI_CALLBACKS callback;
GENI_APIS api;
CRITICAL_SECTION criticalsection;
HANDLE semaphore;
HANDLE heap;
DWORD return_value;
void* userdata;
} GENI_VM;
//COMPILATION SPECIFICS
typedef enum{
SEG_CODE=0,
SEG_DATA,
SEG_UNKNOW
} GENI_SEGMENT;
#ifdef CAN_COMPILE
typedef struct _GENI_COMPILER_NAMESPACE_REF{
DWORD address; //Real address in codesegment / datasegment, *((DWORD)(segement + address)) = ptr...
DWORD source_line; //line in code-source
GENI_SEGMENT segment;
} GENI_COMPILER_NAMESPACE_REF;
typedef struct _GENI_COMPILER_NAMESPACE{
char* name;
DWORD address;
DWORD line_defined;
GENI_SEGMENT segment; //to allow to refer to DATA or CODE labels !
//and a pointer to keep trace of reference to a not yet declared label.
GENI_COMPILER_NAMESPACE_REF* references;
DWORD ref_count;
} GENI_COMPILER_NAMESPACE;
typedef struct _GENI_COMPILER_CONTEXT{
GENI_VM* vm;
DWORD current_line; //current line in the input buffer
DWORD name_count;
GENI_COMPILER_NAMESPACE* names; // an array of names
GENI_SEGMENT current_segment;
GENI_OPCODE* code_segment;
DWORD code_size;
DWORD instruction_count;
BOOL is_operand_left;
BYTE* memory_segment;
DWORD memory_size;
DWORD memory_current_offset;
DWORD memory_max_offset; //keep trace of minimal memory size !
GENI_COMPILER_NAMESPACE* post_build; //used for encryption
//BYTECODE modifiers ...
//MEMORY_STATE (build from source code !)
} GENI_COMPILER_CONTEXT;
#endif
typedef struct _GENI_VM_WATERMARK_ITERATOR{
BYTE byte_idx;
DWORD current_opcode;
GENI_OPCODE* opcodes;
} GENI_VM_WATERMARK_ITERATOR;
typedef struct _GENI_BINARY_HEADER{
DWORD markvm; // = GENI
DWORD markversion; // = VMWW
DWORD memory_size;
DWORD memory_stored;
DWORD instruction_count;
BYTE * data;
} GENI_BINARY_HEADER;
typedef void (fnHandler)(GENI_VM* , GENI_OPCODE* );
#ifdef CAN_COMPILE
#define MAP_OPCODE( VM, handlerptr, opcode, mnemonicstr ) \
VM->opcodeset[ opcode ].handler = (DWORD)handlerptr; \
VM->opcodeset[ opcode ].mnemonic = mnemonicstr;
#else
#define MAP_OPCODE( VM, handlerptr, opcode, mnemonicstr ) \
VM->opcodeset[ opcode ].handler = (DWORD)handlerptr;
#endif
void OPCODE32( GENI_OPCODE* opptr, DWORD opcode,
DWORD oplsize, BYTE oplkind, BYTE oplmode, DWORD oplvalue,
DWORD oprsize, BYTE oprkind, BYTE oprmode, DWORD oprvalue ){
(opptr)->size=OS_DWORD;
(opptr)->instruction=opcode;
(opptr)->leftop.size=oplsize;
(opptr)->leftop.type=oplkind;
(opptr)->leftop.mode=oplmode;
(opptr)->leftop.dword=oplvalue;
(opptr)->rightop.size=oprsize;
(opptr)->rightop.type=oprkind;
(opptr)->rightop.mode=oprmode;
(opptr)->rightop.dword=oprvalue;
}
#ifdef CAN_DUMP
void geni_vm_dump_memory(DWORD address, DWORD offset, DWORD size);
void geni_vm_dump_operand( GENI_OPERAND* operand );
void geni_vm_dump_opcode( GENI_VM* vm, GENI_OPCODE* opcode );
void geni_vm_dump_stack( char* name, GENI_STACK* stack );
void geni_vm_dump( GENI_VM* vm);
#endif
DWORD geni_vm_do_sub(GENI_CALLBACK* cb, DWORD* host_stackpointer);
void geni_vm_run( GENI_VM* vm );
void geni_vm_set_userdata( GENI_VM* vm, void* userdata);
void* geni_vm_get_userdata( GENI_VM* vm);
#endif // #ifdef _VM_HEADER