#include #include #include #include // for easier work with cJSON // How to compile? Like this! // gcc -o disassembler disassembler.c -lcjson // How to run? Like this! // ./disassembler snake.gb // Large chunks of the code are from my Intel 8080 emulator typedef struct buffer { unsigned char* buffer; int length; } buffer; buffer* read_file(char** argv) { FILE* file = fopen(argv[1], "rb"); if (file == NULL) { printf("Issue opening the file.\n"); return NULL; } fseek(file, 0L, SEEK_END); int fsize = ftell(file); fseek(file, 0L, SEEK_SET); buffer *b = malloc(sizeof(buffer)); b->buffer = malloc(fsize); b->length = fsize; fread(b->buffer, fsize, 1, file); fclose(file); return b; } cJSON* read_cjson() { FILE *fs = fopen("Opcodes.json", "rb"); if (fs == NULL) { printf("ERROR: Unable to open the Opcodes.json file.\n"); return NULL; } // read the file contents into a string fseek(fs, 0L, SEEK_END); int fsize = ftell(fs); fseek(fs, 0L, SEEK_SET); buffer *b = malloc(sizeof(buffer)); b->buffer = malloc(fsize); b->length = fsize; fread(b->buffer, fsize, 1, fs); fclose(fs); // parse the JSON data cJSON *json = cJSON_Parse(b->buffer); if (json == NULL) { const char *error_ptr = cJSON_GetErrorPtr(); if (error_ptr != NULL) { printf("Error: %s\n", error_ptr); } cJSON_Delete(json); return NULL; } free(b->buffer); // almost forgot that dataleak free(b); return json; } void print_buffer(buffer* b) { // just a check // equivalent to $ xxd snake.gb for (int i = 0; i < 40; i++) { printf("%02x \n", b->buffer[i]); } } int disassemble8080(buffer* b, int pc, cJSON* json) { unsigned char *code = &(b->buffer[pc]); int opbytes = 1; printf("%04x ", pc); char mnemonic[10]; char opcode_str[5]; sprintf(opcode_str, "0x%02X", *code); //printf("%s\n", opcode_str); if (strcmp(opcode_str, "0xCB") == 0) { pc++; unsigned char *code = &(b->buffer[pc]); sprintf(opcode_str, "0x%02X", *code); //printf("%s\n", opcode_str); cJSON *prefixed = cJSON_GetObjectItem(json, "cbprefixed"); if (prefixed == NULL) { printf("Error: 'prefixed' not found in JSON.\n"); return 0; } cJSON *command = cJSON_GetObjectItem(prefixed, opcode_str); if (command == NULL) { printf("Error: Command with opcode %s not found.\n", opcode_str); return 0; } cJSON *mnemonic_item = cJSON_GetObjectItem(command, "mnemonic"); cJSON *bytes_item = cJSON_GetObjectItem(command, "bytes"); if (mnemonic_item != NULL && cJSON_IsString(mnemonic_item)) { strcpy(mnemonic, mnemonic_item->valuestring); } if (bytes_item != NULL && cJSON_IsNumber(bytes_item)) { opbytes = bytes_item->valueint; } printf("%s \t", mnemonic); // Extract and print operands int operand_count = 0; cJSON *operands = cJSON_GetObjectItem(command, "operands"); if (operands != NULL && cJSON_IsArray(operands)) { operand_count = cJSON_GetArraySize(operands); //printf("Number of operands: %d\n", operand_count); for (int i = 0; i < operand_count; i++) { if (i == 1) { printf(", "); } cJSON *operand = cJSON_GetArrayItem(operands, i); cJSON *name = cJSON_GetObjectItem(operand, "name"); cJSON *immediate = cJSON_GetObjectItem(operand, "immediate"); cJSON *bytes = cJSON_GetObjectItem(operand, "bytes"); if (immediate != NULL && cJSON_IsBool(immediate)) { printf("%s", cJSON_IsTrue(immediate) ? "" : "("); } if (bytes != NULL && cJSON_IsNumber(bytes)) { if (bytes->valueint == 1) { unsigned char *code = &(b->buffer[pc+1]); sprintf(opcode_str, "0x%02X", *code); printf("%s", opcode_str); } if (bytes->valueint == 2) { unsigned char *code = &(b->buffer[pc+2]); sprintf(opcode_str, "0x%02X", *code); printf("%s", opcode_str); sprintf(opcode_str, "%02X", *(code-1)); printf("%s", opcode_str); } } if (name != NULL && cJSON_IsString(name) && (bytes == NULL)) { //printf("Operand %d: %s", i + 1, name->valuestring); printf("%s", name->valuestring); } if (bytes != NULL && cJSON_IsNumber(bytes)) { //printf(", Bytes: %d", bytes->valueint); } if (immediate != NULL && cJSON_IsBool(immediate)) { printf("%s", cJSON_IsTrue(immediate) ? "" : ")"); //printf(", Immediate: %s", cJSON_IsTrue(immediate) ? "true" : "false"); } } } printf("\n"); printf(" ^ We have a prefixed command!\n"); return opbytes+1; } cJSON *unprefixed = cJSON_GetObjectItem(json, "unprefixed"); if (unprefixed == NULL) { printf("Error: 'unprefixed' not found in JSON.\n"); return 0; } cJSON *command = cJSON_GetObjectItem(unprefixed, opcode_str); if (command == NULL) { printf("Error: Command with opcode %s not found.\n", opcode_str); return 0; } cJSON *mnemonic_item = cJSON_GetObjectItem(command, "mnemonic"); cJSON *bytes_item = cJSON_GetObjectItem(command, "bytes"); if (mnemonic_item != NULL && cJSON_IsString(mnemonic_item)) { strcpy(mnemonic, mnemonic_item->valuestring); } if (bytes_item != NULL && cJSON_IsNumber(bytes_item)) { opbytes = bytes_item->valueint; } printf("%s \t", mnemonic); // Extract and print operands int operand_count = 0; cJSON *operands = cJSON_GetObjectItem(command, "operands"); if (operands != NULL && cJSON_IsArray(operands)) { operand_count = cJSON_GetArraySize(operands); //printf("Number of operands: %d\n", operand_count); for (int i = 0; i < operand_count; i++) { if (i == 1) { printf(", "); } cJSON *operand = cJSON_GetArrayItem(operands, i); cJSON *name = cJSON_GetObjectItem(operand, "name"); cJSON *immediate = cJSON_GetObjectItem(operand, "immediate"); cJSON *bytes = cJSON_GetObjectItem(operand, "bytes"); if (immediate != NULL && cJSON_IsBool(immediate)) { printf("%s", cJSON_IsTrue(immediate) ? "" : "("); } if (bytes != NULL && cJSON_IsNumber(bytes)) { if (bytes->valueint == 1) { unsigned char *code = &(b->buffer[pc+1]); sprintf(opcode_str, "0x%02X", *code); printf("%s", opcode_str); } if (bytes->valueint == 2) { unsigned char *code = &(b->buffer[pc+2]); sprintf(opcode_str, "0x%02X", *code); printf("%s", opcode_str); sprintf(opcode_str, "%02X", *(code-1)); printf("%s", opcode_str); } } if (name != NULL && cJSON_IsString(name) && (bytes == NULL)) { //printf("Operand %d: %s", i + 1, name->valuestring); printf("%s", name->valuestring); } if (bytes != NULL && cJSON_IsNumber(bytes)) { //printf(", Bytes: %d", bytes->valueint); } if (immediate != NULL && cJSON_IsBool(immediate)) { printf("%s", cJSON_IsTrue(immediate) ? "" : ")"); //printf(", Immediate: %s", cJSON_IsTrue(immediate) ? "true" : "false"); } } } printf("\n"); return opbytes; } void print_keys(cJSON *json) { // Used only for debug purposes // Lists all the keys cJSON *unprefixed = cJSON_GetObjectItem(json, "unprefixed"); if (unprefixed == NULL) { printf("Error: 'unprefixed' not found in JSON.\n"); return; } cJSON *item = NULL; cJSON_ArrayForEach(item, unprefixed) { printf("Key: %s\n", item->string); } } int main (int argc, char** argv) { int pc = 0x150; //Program Counter, note GB roms typically start at 0x100 buffer* buff = read_file(argv); if (buff == NULL) { printf("Fatal error.\n"); return 1; } //print_buffer(buff); cJSON *json = read_cjson(); if (json == NULL) { printf("main terminated\n"); return 1; } //print_keys(json); while (pc < 0x400) {//buff->length) { pc += disassemble8080(buff, pc, json); } free(buff); cJSON_Delete(json); // basically free(json) return 0; }