├── README.md └── VM.c /README.md: -------------------------------------------------------------------------------- 1 | # Custom-VM 2 | 3 | Virtual machine with a custom instruction set in C. 4 | 5 | Made for the sake of this article : https://resources.infosecinstitute.com/reverse-engineering-virtual-machine-protected-binaries/ 6 | -------------------------------------------------------------------------------- /VM.c: -------------------------------------------------------------------------------- 1 | /* 2 | VM by Souhail Hammou : custom instruction set 3 | data space and stack space are customizable. 4 | Important : In calculations the VM is using unsigned values. 5 | */ 6 | #include 7 | #include 8 | #include 9 | #define TRUE 1 10 | #define FALSE 0 11 | typedef unsigned char boolean; 12 | typedef uint8_t BYTE; 13 | typedef uint16_t WORD; 14 | typedef uint32_t DWORD; 15 | typedef struct 16 | { 17 | /*data has also the code*/ 18 | BYTE data[4096]; 19 | /*stack space , size of one element is WORD in order to be able to push addresses*/ 20 | WORD stack[256]; 21 | }ADDRESS_SPACE,*PADDRESS_SPACE; 22 | typedef struct 23 | { 24 | /*General Purpose Registers R0 -> R3*/ 25 | WORD GPRs[4]; 26 | union 27 | { 28 | unsigned char Flags; 29 | struct 30 | { 31 | unsigned char ZF:1; 32 | unsigned char CF:1; 33 | unsigned char Unused:6; 34 | }; 35 | }; 36 | WORD IP; 37 | WORD SP; 38 | }REGS,*PREGS; 39 | void VmLoop(PADDRESS_SPACE AS,PREGS Regs) 40 | { 41 | int i; 42 | boolean exit = FALSE; 43 | BYTE opcode,byte_val,byte_val2,byte_val3; 44 | WORD word_val,word_val2; 45 | while(!exit) 46 | { 47 | /*read byte (opcode)*/ 48 | //printf("[+] IP : %.4X => ",Regs->IP); 49 | opcode = AS->data[Regs->IP++]; 50 | /*opcodes switch*/ 51 | switch(opcode) 52 | { 53 | case 0x90 : 54 | //printf("NOP\n"); 55 | break; 56 | /* 57 | Each nibble of the operand represents a General purpose register (GPR) 58 | the highest nibble is the destination , the lowest one is the source. 59 | Example: 60 | 10 12 => MOV R1,R2 61 | 10 11 => MOV R1,R1 62 | 10 01 => MOV R0,R1 63 | */ 64 | case 0x10 : 65 | byte_val = AS->data[Regs->IP++]; 66 | if((byte_val & 0xF0) <= 0x30 && (byte_val & 0x0F) <= 3) 67 | { 68 | Regs->GPRs[(byte_val & 0xF0)>>4] = Regs->GPRs[byte_val & 0x0F]; 69 | //printf("MOV R%d,R%d\n",(byte_val & 0xF0)>>4,byte_val & 0x0F); 70 | } 71 | else 72 | goto exception; 73 | break; 74 | /* 75 | Move and extend byte from memory to register 76 | Example: 77 | 12 03 50 00 => MOVX R3,BYTE [0050] 78 | 12 00 00 01 => MOVX R0,BYTE [0100] 79 | */ 80 | case 0x12 : 81 | byte_val = AS->data[Regs->IP++]; 82 | if(byte_val > 3) 83 | goto exception; 84 | word_val = *(WORD*)&AS->data[Regs->IP]; 85 | Regs->IP += 2; 86 | if(word_val >= sizeof(AS->data)) 87 | goto exception; 88 | Regs->GPRs[byte_val] = 0; 89 | *(BYTE*)&Regs->GPRs[byte_val] = AS->data[word_val]; 90 | //printf("MOVX R%d, BYTE [%.4X]\n",byte_val,word_val); 91 | break; 92 | /* 93 | Move word from memory to register 94 | 14 03 50 00 => MOV R3,WORD [0050] 95 | 14 00 00 01 => MOV R0,WORD [0100] 96 | */ 97 | case 0x14 : 98 | byte_val = AS->data[Regs->IP++]; 99 | if(byte_val > 3) 100 | goto exception; 101 | word_val = *(WORD*)&AS->data[Regs->IP]; 102 | Regs->IP += 2; 103 | if(word_val >= sizeof(AS->data)) 104 | goto exception; 105 | Regs->GPRs[byte_val] = *(WORD*)&AS->data[word_val]; 106 | //printf("MOV R%d, WORD [%.4X]\n",byte_val,word_val); 107 | break; 108 | /* 109 | Move and extend byte to register 110 | 16 01 15 => MOVX R1,15h 111 | */ 112 | case 0x16 : 113 | byte_val = AS->data[Regs->IP++]; 114 | if(byte_val > 3) 115 | goto exception; 116 | Regs->GPRs[byte_val] = 0; 117 | *(BYTE*)&Regs->GPRs[byte_val] = AS->data[Regs->IP++]; 118 | //printf("MOVX R%d,%.2Xh\n",byte_val,AS->data[Regs->IP - 1]); 119 | break; 120 | /* 121 | Move word to register 122 | 18 01 15 28 => MOV R1,2815h 123 | */ 124 | case 0x18 : 125 | byte_val = AS->data[Regs->IP++]; 126 | if(byte_val > 3) 127 | goto exception; 128 | Regs->GPRs[byte_val] = 0; 129 | Regs->GPRs[byte_val] = *(WORD*)&AS->data[Regs->IP]; 130 | //printf("MOV R%d,%.4Xh\n",byte_val,*(WORD*)&AS->data[Regs->IP]); 131 | Regs->IP += sizeof(WORD); 132 | break; 133 | /* 134 | Move byte from register to memory location 135 | ex : 136 | 1C 01 20 01 => MOV BYTE [0120],R1 137 | 1C 03 50 03 => MOV BYTE [0350],R3 138 | */ 139 | case 0x1c : 140 | byte_val = AS->data[Regs->IP++]; 141 | if(byte_val > 3) 142 | goto exception; 143 | word_val = *(WORD*)&AS->data[Regs->IP]; 144 | Regs->IP += 2; 145 | if(word_val >= sizeof(AS->data)) 146 | goto exception; 147 | AS->data[word_val] = *(BYTE*)&Regs->GPRs[byte_val]; 148 | //printf("MOV BYTE [%.4X],R%d\n",word_val,byte_val); 149 | break; 150 | /* 151 | Move word from register to memory location 152 | ex : 153 | 1F 01 20 01 => MOV WORD [0120],R1 154 | 1F 03 50 03 => MOV WORD [0350],R3 155 | */ 156 | case 0x1f : 157 | byte_val = AS->data[Regs->IP++]; 158 | if(byte_val > 3) 159 | goto exception; 160 | word_val = *(WORD*)&AS->data[Regs->IP]; 161 | Regs->IP += 2; 162 | if(word_val >= sizeof(AS->data)) 163 | goto exception; 164 | *(WORD*)&AS->data[word_val] = Regs->GPRs[byte_val]; 165 | //printf("MOV WORD [%.4X],R%d\n",word_val,byte_val); 166 | break; 167 | /* 168 | Unconditional Jump 169 | example : 170 | E0 10 00 => JMP 0010 171 | E0 54 02 => JMP 0254 172 | */ 173 | case 0xE0 : 174 | word_val = *(WORD*)&AS->data[Regs->IP]; 175 | Regs->IP += 2; 176 | if(word_val > sizeof(AS->data)) 177 | goto exception; 178 | Regs->IP = word_val; 179 | //printf("JMP %.4X\n",word_val); 180 | break; 181 | /* 182 | JZ : Jump if equal 183 | E2 54 01 =>JNZ 0154 184 | */ 185 | case 0xE2 : 186 | word_val = *(WORD*)&AS->data[Regs->IP]; 187 | Regs->IP += 2; 188 | if(word_val > sizeof(AS->data)) 189 | goto exception; 190 | /*Jump if ZF is set*/ 191 | if(Regs->ZF) 192 | Regs->IP = word_val; 193 | //printf("JZ %.4X\n",word_val); 194 | break; 195 | /* 196 | JNZ : Jump if not equal 197 | E3 54 01 => JNZ 0154 198 | */ 199 | case 0xE3 : 200 | word_val = *(WORD*)&AS->data[Regs->IP]; 201 | Regs->IP += 2; 202 | if(word_val > sizeof(AS->data)) 203 | goto exception; 204 | if(! Regs->ZF) 205 | Regs->IP = word_val; 206 | //printf("JNZ %.4X\n",word_val); 207 | break; 208 | /* 209 | JAE : Jump if above or equal 210 | E4 54 01 : JAE 0154 211 | */ 212 | case 0xE4 : 213 | word_val = *(WORD*)&AS->data[Regs->IP]; 214 | Regs->IP += 2; 215 | if(word_val > sizeof(AS->data)) 216 | goto exception; 217 | if(Regs->ZF || ! Regs->CF) 218 | Regs->IP = word_val; 219 | //printf("JAE %.4X\n",word_val); 220 | break; 221 | /* 222 | JBE : Jump if below or equal 223 | E6 54 01 : JBE 0154 224 | */ 225 | case 0xE6 : 226 | word_val = *(WORD*)&AS->data[Regs->IP]; 227 | Regs->IP += 2; 228 | if(word_val > sizeof(AS->data)) 229 | goto exception; 230 | if(Regs->ZF || Regs->CF) 231 | Regs->IP = word_val; 232 | //printf("JBE %.4X\n",word_val); 233 | break; 234 | /* 235 | JB : Jump if below 236 | E8 54 01 : JB 0154 237 | */ 238 | case 0xE8 : 239 | word_val = *(WORD*)&AS->data[Regs->IP]; 240 | Regs->IP += 2; 241 | if(word_val > sizeof(AS->data)) 242 | goto exception; 243 | if(Regs->CF && ! Regs->ZF) 244 | Regs->IP = word_val; 245 | //printf("JB %.4X\n",word_val); 246 | break; 247 | /* 248 | JA : Jump if above 249 | EC 54 01 => JA 0154 250 | */ 251 | case 0xEC : 252 | word_val = *(WORD*)&AS->data[Regs->IP]; 253 | Regs->IP += 2; 254 | if(word_val > sizeof(AS->data)) 255 | goto exception; 256 | if( ! Regs->CF && ! Regs->ZF) 257 | Regs->IP = word_val; 258 | //printf("JA %.4X\n",word_val); 259 | break; 260 | /*=======================================================*/ 261 | /*ARITHMETIC OPERATIONS ON THE WHOLE REGISTER (WORD)*/ 262 | /* 263 | ADD : Add value to register 264 | AD 01 15 00 : ADD R1,15h 265 | AD 01 01 50 : ADD R1,5001h 266 | 267 | Updated flags : 268 | ZF and CF 269 | */ 270 | case 0xAD : 271 | byte_val = AS->data[Regs->IP++]; 272 | if(byte_val > 3) 273 | goto exception; 274 | word_val = *(WORD*)&AS->data[Regs->IP]; 275 | Regs->IP += 2; 276 | word_val2 = Regs->GPRs[byte_val] + word_val; 277 | if(word_val2 == 0) 278 | Regs->ZF = 1; 279 | else 280 | Regs->ZF = 0; 281 | if(word_val2 < Regs->GPRs[byte_val]) 282 | Regs->CF = 1; 283 | else 284 | Regs->CF = 0; 285 | Regs->GPRs[byte_val] = word_val2; 286 | //printf("ADD R%d,%.4X\n",byte_val,word_val); 287 | break; 288 | /* 289 | ADD : Add 2 registers 290 | A5 12 : ADD R1,R2 291 | A5 30 : ADD R3,R0 292 | */ 293 | case 0xA5 : 294 | byte_val = AS->data[Regs->IP++]; 295 | if((byte_val & 0xF0) <= 0x30 && (byte_val & 0x0F) <= 3) 296 | { 297 | word_val = Regs->GPRs[(byte_val & 0xF0)>>4]; 298 | word_val2 = Regs->GPRs[(byte_val & 0xF0)>>4] += Regs->GPRs[byte_val & 0x0F]; 299 | if(word_val2 == 0) 300 | Regs->ZF = 1; 301 | else 302 | Regs->ZF = 0; 303 | if(word_val2 < word_val) 304 | Regs->CF = 1; 305 | else 306 | Regs->CF = 0; 307 | } 308 | else 309 | goto exception; 310 | //printf("ADD R%d,R%d\n",(byte_val & 0xF0)>>4,byte_val & 0x0F); 311 | break; 312 | /* 313 | ADDL : Add 2 registers (low byte) 314 | A2 12 => ADDL R1,R2 315 | */ 316 | case 0xA2 : 317 | byte_val = AS->data[Regs->IP++]; 318 | if((byte_val & 0xF0) <= 0x30 && (byte_val & 0x0F) <= 3) 319 | { 320 | byte_val2 = *(BYTE*)&Regs->GPRs[(byte_val & 0xF0)>>4]; 321 | byte_val3 = *(BYTE*)&Regs->GPRs[(byte_val & 0xF0)>>4] += *(BYTE*)&Regs->GPRs[byte_val & 0x0F]; 322 | if(byte_val3 == 0) 323 | Regs->ZF = 1; 324 | else 325 | Regs->ZF = 0; 326 | if(byte_val3 < byte_val2) 327 | Regs->CF = 1; 328 | else 329 | Regs->CF = 0; 330 | } 331 | else 332 | goto exception; 333 | //printf("ADDL R%d,R%d\n",(byte_val & 0xF0)>>4,byte_val & 0x0F); 334 | break; 335 | /* 336 | SUB : substract value from register 337 | 5B 01 15 00 : SUB R1,15h 338 | 5B 01 01 50 : SUB R1,5001h 339 | 340 | Updated flags : 341 | ZF and CF 342 | */ 343 | case 0x5B : 344 | byte_val = AS->data[Regs->IP++]; 345 | if(byte_val > 3) 346 | goto exception; 347 | word_val = *(WORD*)&AS->data[Regs->IP]; 348 | Regs->IP += 2; 349 | word_val2 = Regs->GPRs[byte_val] - word_val; 350 | if(word_val2 == 0) 351 | Regs->ZF = 1; 352 | else 353 | Regs->ZF = 0; 354 | if(word_val2 > Regs->GPRs[byte_val]) 355 | Regs->CF = 1; 356 | else 357 | Regs->CF = 0; 358 | Regs->GPRs[byte_val] = word_val2; 359 | //printf("SUB R%d,%.4X\n",byte_val,word_val); 360 | break; 361 | /* 362 | SUB : substract registers (word) 363 | 5C 01 => SUB R0,R1 364 | */ 365 | case 0x5C : 366 | byte_val = AS->data[Regs->IP++]; 367 | if((byte_val & 0xF0) <= 0x30 && (byte_val & 0x0F) <= 3) 368 | { 369 | word_val = Regs->GPRs[(byte_val & 0xF0)>>4]; 370 | word_val2 = Regs->GPRs[(byte_val & 0xF0)>>4] -= Regs->GPRs[byte_val & 0x0F]; 371 | if(word_val2 == 0) 372 | Regs->ZF = 1; 373 | else 374 | Regs->ZF = 0; 375 | if(word_val2 > word_val) 376 | Regs->CF = 1; 377 | else 378 | Regs->CF = 0; 379 | } 380 | else 381 | goto exception; 382 | //printf("SUB R%d,R%d",(byte_val & 0xF0)>>4,byte_val & 0x0F); 383 | break; 384 | /* 385 | SUBL : Substract 2 registers (low part) 386 | 5D 12 => SUBL R1,R2 387 | */ 388 | case 0x5D : 389 | byte_val = AS->data[Regs->IP++]; 390 | if((byte_val & 0xF0) <= 0x30 && (byte_val & 0x0F) <= 3) 391 | { 392 | byte_val2 = *(BYTE*)&Regs->GPRs[(byte_val & 0xF0)>>4]; 393 | byte_val3 = *(BYTE*)&Regs->GPRs[(byte_val & 0xF0)>>4] -= *(BYTE*)&Regs->GPRs[byte_val & 0x0F]; 394 | if(byte_val3 == 0) 395 | Regs->ZF = 1; 396 | else 397 | Regs->ZF = 0; 398 | if(byte_val3 > byte_val2) 399 | Regs->CF = 1; 400 | else 401 | Regs->CF = 0; 402 | } 403 | else 404 | goto exception; 405 | //printf("SUBL R%d,R%d",(byte_val & 0xF0)>>4,byte_val & 0x0F); 406 | break; 407 | /* 408 | XOR : Xor 2 registers 409 | (operand uses nibbles : high = dest , low = source) 410 | F0 12 => XOR R1,R2 411 | F0 01 => XOR R0,R1 412 | */ 413 | case 0xF0 : 414 | byte_val = AS->data[Regs->IP++]; 415 | if((byte_val & 0xF0) <= 0x30 && (byte_val & 0x0F) <= 3) 416 | { 417 | word_val = Regs->GPRs[(byte_val & 0xF0)>>4] ^= Regs->GPRs[byte_val & 0x0F]; 418 | if(word_val == 0) 419 | Regs->ZF = 1; 420 | else 421 | Regs->ZF = 0; 422 | Regs->CF = 0; 423 | } 424 | else 425 | goto exception; 426 | //printf("XOR R%d,R%d\n",(byte_val & 0xF0)>>4,byte_val & 0x0F); 427 | break; 428 | /*===============================================================*/ 429 | /*ARITHMETIC OPERATIONS ON THE LOWER BYTE OF THE REGISTER*/ 430 | /* 431 | XORL : Xor the lower bytes of 2 registers 432 | F1 12 : XORL R1,R2 433 | F1 01 : XORL R0,R1 434 | */ 435 | case 0xF1 : 436 | byte_val = AS->data[Regs->IP++]; 437 | if((byte_val & 0xF0) <= 0x30 && (byte_val & 0x0F) <= 3) 438 | { 439 | byte_val2 = *(BYTE*)&Regs->GPRs[(byte_val & 0xF0)>>4] ^= *(BYTE*)&Regs->GPRs[byte_val & 0x0F]; 440 | if(byte_val2 == 0) 441 | Regs->ZF = 1; 442 | else 443 | Regs->ZF = 0; 444 | Regs->CF = 0; 445 | } 446 | else 447 | goto exception; 448 | //printf("XORL R%d,R%d\n",(byte_val & 0xF0)>>4,byte_val & 0x0F); 449 | break; 450 | /* 451 | ADDL : add only to the lower of the register 452 | A1 03 20 => ADDL R3,20h 453 | */ 454 | case 0xA1: 455 | byte_val = AS->data[Regs->IP++]; 456 | if(byte_val > 3) 457 | goto exception; 458 | byte_val2 = AS->data[Regs->IP++]; 459 | byte_val3 = *(BYTE*)&Regs->GPRs[byte_val] + byte_val2; 460 | if(byte_val3 == 0) 461 | Regs->ZF = 1; 462 | else 463 | Regs->ZF = 0; 464 | if(byte_val3 < *(BYTE*)&Regs->GPRs[byte_val]) 465 | Regs->CF = 1; 466 | else 467 | Regs->CF = 0; 468 | *(BYTE*)&Regs->GPRs[byte_val] = byte_val3; 469 | //printf("ADDL R%d,%.2X\n",byte_val,byte_val2); 470 | break; 471 | /* 472 | SUBL : Substract only from the lower byte of the register 473 | 51 03 20 => SUBL R3,20h 474 | */ 475 | case 0x51: 476 | byte_val = AS->data[Regs->IP++]; 477 | if(byte_val > 3) 478 | goto exception; 479 | byte_val2 = AS->data[Regs->IP++]; 480 | byte_val3 = *(BYTE*)&Regs->GPRs[byte_val] - byte_val2; 481 | if(byte_val3 == 0) 482 | Regs->ZF = 1; 483 | else 484 | Regs->ZF = 0; 485 | if(byte_val3 > *(BYTE*)&Regs->GPRs[byte_val]) 486 | Regs->CF = 1; 487 | else 488 | Regs->CF = 0; 489 | *(BYTE*)&Regs->GPRs[byte_val] = byte_val3; 490 | //printf("SUBL R%d,%.2X\n",byte_val,byte_val2); 491 | break; 492 | /*===============================================================*/ 493 | /* 494 | Store register (low byte) at [Rx]. 495 | 55 21 => MOV BYTE [R2],R1 496 | */ 497 | case 0x55 : 498 | byte_val = AS->data[Regs->IP++]; 499 | if((byte_val & 0xF0) <= 0x30 && (byte_val & 0x0F) <= 3 && Regs->GPRs[(byte_val & 0xF0)>>4] < sizeof(AS->data)) 500 | AS->data[Regs->GPRs[(byte_val & 0xF0)>>4]] = *(BYTE*)&Regs->GPRs[byte_val & 0x0F]; 501 | else 502 | goto exception; 503 | //printf("MOV BYTE [R%d],R%d\n",(byte_val & 0xF0)>>4,byte_val & 0x0F); 504 | break; 505 | /* 506 | Load and extend low byte of register from memory pointed by a register 507 | 56 21 => MOV R2,BYTE [R1] 508 | */ 509 | case 0x56 : 510 | byte_val = AS->data[Regs->IP++]; 511 | if((byte_val & 0xF0) <= 0x30 && (byte_val & 0x0F) <= 3 && Regs->GPRs[(byte_val & 0x0F)] < sizeof(AS->data)) 512 | { 513 | *(BYTE*)&Regs->GPRs[(byte_val & 0xF0)>>4] = AS->data[Regs->GPRs[byte_val & 0x0F]]; 514 | Regs->GPRs[(byte_val & 0xF0)>>4] &= 0xFF; 515 | } 516 | else 517 | goto exception; 518 | //printf("MOVX R%d, BYTE [R%d]\n",(byte_val & 0xF0)>>4,byte_val & 0x0F); 519 | break; 520 | /* 521 | CMP : Compare 2 registers (word) 522 | 70 12 : CMP R1,R2 523 | */ 524 | case 0x70 : 525 | byte_val = AS->data[Regs->IP++]; 526 | if((byte_val & 0xF0) <= 0x30 && (byte_val & 0x0F) <= 3 && Regs->GPRs[(byte_val & 0x0F)] < sizeof(AS->data)) 527 | { 528 | word_val = Regs->GPRs[(byte_val & 0xF0)>>4]; 529 | word_val2 = Regs->GPRs[byte_val & 0x0F]; 530 | if(word_val2 == word_val) 531 | Regs->ZF = 1; 532 | else 533 | Regs->ZF = 0; 534 | if(word_val2 > word_val) 535 | Regs->CF = 1; 536 | else 537 | Regs->CF = 0; 538 | } 539 | else 540 | goto exception; 541 | //printf("CMP R%d,R%d\n",(byte_val & 0xF0)>>4,byte_val & 0x0F); 542 | break; 543 | /* 544 | CMPL : Compare 2 registers (lower byte) 545 | 71 12 : CMPL R1,R2 546 | */ 547 | case 0x71 : 548 | byte_val = AS->data[Regs->IP++]; 549 | if((byte_val & 0xF0) <= 0x30 && (byte_val & 0x0F) <= 3 && Regs->GPRs[(byte_val & 0x0F)] < sizeof(AS->data)) 550 | { 551 | byte_val2 = *(BYTE*)&Regs->GPRs[(byte_val & 0xF0)>>4]; 552 | byte_val3 = *(BYTE*)&Regs->GPRs[byte_val & 0x0F]; 553 | if(byte_val3 == byte_val2) 554 | Regs->ZF = 1; 555 | else 556 | Regs->ZF = 0; 557 | if(byte_val3 > byte_val2) 558 | Regs->CF = 1; 559 | else 560 | Regs->CF = 0; 561 | } 562 | else 563 | goto exception; 564 | //printf("CMP R%d,R%d\n",(byte_val & 0xF0)>>4,byte_val & 0x0F); 565 | break; 566 | /* 567 | Push register 568 | example : AF 01 => PUSH R1 569 | */ 570 | case 0xAF : 571 | byte_val = AS->data[Regs->IP++]; 572 | if(byte_val > 3) 573 | goto exception; 574 | /*Decrement the stack pointer to store the new value*/ 575 | Regs->SP--; 576 | /*Check for stack overflow*/ 577 | if(Regs->SP == 0xFFFF) 578 | goto exception; 579 | /*Push value */ 580 | AS->stack[Regs->SP] = Regs->GPRs[byte_val]; 581 | //printf("PUSH R%d\n",byte_val); 582 | break; 583 | /* 584 | Pop a register 585 | AE 01 => POP R1 586 | */ 587 | case 0xAE : 588 | byte_val = AS->data[Regs->IP++]; 589 | if(byte_val > 3) 590 | goto exception; 591 | /* 592 | Check for stack underflow 593 | */ 594 | if(&AS->stack[Regs->SP] == &AS->stack[sizeof(AS->stack)/sizeof(WORD)]) 595 | goto exception; 596 | /*Move the value into the register*/ 597 | Regs->GPRs[byte_val] = AS->stack[Regs->SP]; 598 | /*Value popped , increment SP*/ 599 | Regs->SP++; 600 | //printf("POP R%d\n",byte_val); 601 | break; 602 | /*========================================================*/ 603 | /*User interaction operations (print and receive input)*/ 604 | /* 605 | Print Word to user as integer, the value must be at the top of the stack and it is popped 606 | C0 => print integer 607 | */ 608 | case 0xC0 : 609 | /*read value then pop it*/ 610 | if(&AS->stack[Regs->SP] == &AS->stack[sizeof(AS->stack)/sizeof(WORD)]) 611 | goto exception; 612 | word_val = AS->stack[Regs->SP++]; 613 | //printf("Print integer\n"); 614 | printf("%u\n",word_val); 615 | break; 616 | /* 617 | Print string to user, the pointer must be at the top of the stack and it is popped 618 | C2 => print string 619 | */ 620 | case 0xC2 : 621 | if(&AS->stack[Regs->SP] == &AS->stack[sizeof(AS->stack)/sizeof(WORD)]) 622 | goto exception; 623 | /*read it and pop it*/ 624 | word_val = AS->stack[Regs->SP++]; 625 | if(word_val > sizeof(AS->data)) 626 | goto exception; 627 | //printf("Print string\n"); 628 | printf("%s",&AS->data[word_val]); 629 | break; 630 | /* 631 | Scan string from user, the pointer where to store the integer must be on top of the stack 632 | 89 633 | */ 634 | case 0x89 : 635 | if(&AS->stack[Regs->SP] == &AS->stack[sizeof(AS->stack)/sizeof(WORD)]) 636 | goto exception; 637 | /*read it and pop it*/ 638 | word_val = AS->stack[Regs->SP++]; 639 | if(word_val > sizeof(AS->data)) 640 | goto exception; 641 | //printf("Scan string\n"); 642 | //printf(" [+] Input : "); 643 | gets((char*)&AS->data[word_val]); 644 | break; 645 | /*=======================================================*/ 646 | /*0xDB Debugging Only*/ 647 | /* 648 | case 0xDB : 649 | printf("\n===Debug Information Start===\n"); 650 | printf("+ Registers :\n"); 651 | for(i=0;i<=3;i++) 652 | printf(" R%d : 0x%.4X\n",i,Regs->GPRs[i]); 653 | printf(" IP : 0x%.4X\n",Regs->IP); 654 | printf(" SP : 0x%.4X\n",Regs->SP*sizeof(WORD)); 655 | printf("+ Current Stack : (Top 4 values)\n"); 656 | if(Regs->SP == sizeof(AS->stack)/sizeof(WORD)) 657 | { 658 | printf(" The stack is empty.\n"); 659 | goto loc; 660 | } 661 | for(i=0;i<4;i++) 662 | { 663 | if(Regs->SP + i < sizeof(AS->stack)/sizeof(WORD)) 664 | printf(" SP+%d => 0x%.4X : %.4X\n",i*2,(Regs->SP + i)*2,AS->stack[Regs->SP+i]); 665 | } 666 | loc: 667 | printf("+Flags Information :\n"); 668 | printf(" Flags = 0x%.2X\n",Regs->Flags); 669 | printf(" ZF = %d\n",Regs->ZF); 670 | printf(" CF = %d\n",Regs->CF); 671 | printf("===Debug Information End ===\n\n"); 672 | break; 673 | */ 674 | /*======================================================*/ 675 | case 0xED : 676 | //printf("Exit\n"); 677 | exit = TRUE; 678 | break; 679 | default : 680 | exception: 681 | //printf("\n==Exception : ...Exiting==\n"); 682 | exit = TRUE; 683 | } 684 | } 685 | } 686 | int main() 687 | { 688 | PADDRESS_SPACE AS; 689 | PREGS Regs; 690 | int size; 691 | FILE* File; 692 | //printf("DEBUG INFO :"); 693 | //printf("Allocating Address Space\n"); 694 | AS = (PADDRESS_SPACE) malloc(sizeof(ADDRESS_SPACE)); 695 | //printf("Allocating Registers\n"); 696 | Regs = (PREGS) malloc(sizeof(REGS)); 697 | //printf("Initializing Registers\n"); 698 | Regs->IP = 0; 699 | Regs->SP = sizeof(AS->stack) / sizeof(WORD); 700 | Regs->Flags = 0; 701 | /*Open code and data file and read it into */ 702 | File = fopen("vm_file","rb"); 703 | if(!File) 704 | { 705 | printf("Found trouble opening the file"); 706 | return 0; 707 | } 708 | /*Check the file size*/ 709 | fseek(File,0,SEEK_END); 710 | size = ftell(File); 711 | if( size > sizeof(AS->data)) 712 | { 713 | printf("File size is larger than the storage available for data and code"); 714 | return 0; 715 | } 716 | rewind(File); 717 | /*Copy the file to our VM address space*/ 718 | fread(AS->data,1,size,File); 719 | fclose(File); 720 | //printf("Starting Execution\n"); 721 | VmLoop(AS,Regs); 722 | _getch(); 723 | return 0; 724 | } 725 | --------------------------------------------------------------------------------