2024-08-19 15:41:54 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
2024-08-28 15:34:26 +00:00
|
|
|
#include <cjson/cJSON.h>
|
|
|
|
#include <string.h> // for easier work with cJSON
|
2024-08-19 15:41:54 +00:00
|
|
|
|
|
|
|
// How to compile? Like this!
|
2024-08-28 15:34:26 +00:00
|
|
|
// gcc -o disassembler disassembler.c -lcjson
|
2024-08-19 15:41:54 +00:00
|
|
|
|
2024-08-28 16:02:40 +00:00
|
|
|
// How to run? Like this!
|
|
|
|
// ./disassembler snake.gb
|
|
|
|
|
2024-08-19 15:41:54 +00:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2024-08-28 15:34:26 +00:00
|
|
|
cJSON* read_cjson() {
|
|
|
|
FILE *fs = fopen("Opcodes.json", "rb");
|
2024-08-28 16:02:40 +00:00
|
|
|
if (fs == NULL) {
|
2024-08-28 15:34:26 +00:00
|
|
|
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;
|
|
|
|
}
|
2024-08-28 16:02:40 +00:00
|
|
|
free(b->buffer); // almost forgot that dataleak
|
2024-08-28 15:34:26 +00:00
|
|
|
free(b);
|
|
|
|
return json;
|
|
|
|
}
|
|
|
|
|
2024-08-19 15:41:54 +00:00
|
|
|
void print_buffer(buffer* b) {
|
2024-08-28 16:02:40 +00:00
|
|
|
// just a check
|
|
|
|
// equivalent to $ xxd snake.gb
|
2024-08-19 15:41:54 +00:00
|
|
|
for (int i = 0; i < 40; i++) {
|
|
|
|
printf("%02x \n", b->buffer[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-28 15:34:26 +00:00
|
|
|
int disassemble8080(buffer* b, int pc, cJSON* json) {
|
2024-08-19 15:41:54 +00:00
|
|
|
unsigned char *code = &(b->buffer[pc]);
|
|
|
|
int opbytes = 1;
|
|
|
|
printf("%04x ", pc);
|
2024-08-28 15:34:26 +00:00
|
|
|
char mnemonic[10];
|
|
|
|
|
2024-08-28 17:48:32 +00:00
|
|
|
char opcode_str[5];
|
|
|
|
sprintf(opcode_str, "0x%02X", *code);
|
2024-09-05 17:25:22 +00:00
|
|
|
//printf("%s\n", opcode_str);
|
2024-08-28 17:48:32 +00:00
|
|
|
|
2024-09-02 11:52:53 +00:00
|
|
|
|
|
|
|
if (strcmp(opcode_str, "0xCB") == 0) {
|
2024-09-05 17:25:22 +00:00
|
|
|
pc++;
|
|
|
|
unsigned char *code = &(b->buffer[pc]);
|
2024-09-02 11:52:53 +00:00
|
|
|
|
|
|
|
sprintf(opcode_str, "0x%02X", *code);
|
2024-09-05 17:25:22 +00:00
|
|
|
//printf("%s\n", opcode_str);
|
2024-09-02 11:52:53 +00:00
|
|
|
|
|
|
|
cJSON *prefixed = cJSON_GetObjectItem(json, "cbprefixed");
|
2024-09-05 17:25:22 +00:00
|
|
|
if (prefixed == NULL) {
|
|
|
|
printf("Error: 'prefixed' not found in JSON.\n");
|
2024-09-02 11:52:53 +00:00
|
|
|
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");
|
|
|
|
|
2024-09-05 17:25:22 +00:00
|
|
|
|
|
|
|
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");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-09-02 11:52:53 +00:00
|
|
|
|
|
|
|
|
|
|
|
printf("\n");
|
2024-09-05 17:25:22 +00:00
|
|
|
printf(" ^ We have a prefixed command!\n");
|
2024-09-05 11:01:03 +00:00
|
|
|
return opbytes+1;
|
2024-09-02 11:52:53 +00:00
|
|
|
|
|
|
|
}
|
2024-08-19 15:41:54 +00:00
|
|
|
|
2024-08-28 15:34:26 +00:00
|
|
|
cJSON *unprefixed = cJSON_GetObjectItem(json, "unprefixed");
|
|
|
|
if (unprefixed == NULL) {
|
|
|
|
printf("Error: 'unprefixed' not found in JSON.\n");
|
2024-09-02 11:52:53 +00:00
|
|
|
return 0;
|
2024-08-28 15:34:26 +00:00
|
|
|
}
|
2024-08-28 17:48:32 +00:00
|
|
|
cJSON *command = cJSON_GetObjectItem(unprefixed, opcode_str);
|
2024-08-28 15:34:26 +00:00
|
|
|
if (command == NULL) {
|
2024-08-28 17:48:32 +00:00
|
|
|
printf("Error: Command with opcode %s not found.\n", opcode_str);
|
2024-08-28 15:34:26 +00:00
|
|
|
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)) {
|
2024-08-28 16:02:40 +00:00
|
|
|
opbytes = bytes_item->valueint;
|
2024-08-28 15:34:26 +00:00
|
|
|
}
|
|
|
|
|
2024-09-05 17:25:22 +00:00
|
|
|
printf("%s \t", mnemonic);
|
2024-09-02 11:52:53 +00:00
|
|
|
|
2024-09-05 11:01:03 +00:00
|
|
|
// 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);
|
2024-09-05 17:25:22 +00:00
|
|
|
//printf("Number of operands: %d\n", operand_count);
|
2024-09-05 11:01:03 +00:00
|
|
|
for (int i = 0; i < operand_count; i++) {
|
2024-09-05 17:25:22 +00:00
|
|
|
if (i == 1) {
|
|
|
|
printf(", ");
|
|
|
|
}
|
2024-09-05 11:01:03 +00:00
|
|
|
cJSON *operand = cJSON_GetArrayItem(operands, i);
|
|
|
|
cJSON *name = cJSON_GetObjectItem(operand, "name");
|
2024-09-05 11:45:12 +00:00
|
|
|
cJSON *immediate = cJSON_GetObjectItem(operand, "immediate");
|
2024-09-05 17:25:22 +00:00
|
|
|
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);
|
2024-09-05 11:01:03 +00:00
|
|
|
}
|
|
|
|
if (bytes != NULL && cJSON_IsNumber(bytes)) {
|
2024-09-05 17:25:22 +00:00
|
|
|
//printf(", Bytes: %d", bytes->valueint);
|
2024-09-05 11:01:03 +00:00
|
|
|
}
|
2024-09-05 11:45:12 +00:00
|
|
|
if (immediate != NULL && cJSON_IsBool(immediate)) {
|
2024-09-05 17:25:22 +00:00
|
|
|
printf("%s", cJSON_IsTrue(immediate) ? "" : ")");
|
|
|
|
//printf(", Immediate: %s", cJSON_IsTrue(immediate) ? "true" : "false");
|
2024-09-05 11:45:12 +00:00
|
|
|
}
|
2024-09-05 11:01:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-02 11:52:53 +00:00
|
|
|
|
2024-08-19 15:41:54 +00:00
|
|
|
printf("\n");
|
|
|
|
return opbytes;
|
|
|
|
}
|
|
|
|
|
2024-08-28 17:48:32 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
2024-08-19 15:41:54 +00:00
|
|
|
|
|
|
|
|
|
|
|
int main (int argc, char** argv) {
|
2024-09-05 11:01:03 +00:00
|
|
|
int pc = 0x150; //Program Counter, note GB roms typically start at 0x100
|
2024-08-19 15:41:54 +00:00
|
|
|
|
|
|
|
buffer* buff = read_file(argv);
|
|
|
|
if (buff == NULL) {
|
|
|
|
printf("Fatal error.\n");
|
|
|
|
return 1;
|
|
|
|
}
|
2024-09-02 11:52:53 +00:00
|
|
|
//print_buffer(buff);
|
2024-08-28 16:02:40 +00:00
|
|
|
cJSON *json = read_cjson();
|
2024-08-28 15:34:26 +00:00
|
|
|
|
|
|
|
if (json == NULL) {
|
|
|
|
printf("main terminated\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2024-08-28 17:48:32 +00:00
|
|
|
//print_keys(json);
|
|
|
|
|
2024-08-28 15:34:26 +00:00
|
|
|
|
2024-09-02 11:52:53 +00:00
|
|
|
while (pc < 0x400) {//buff->length) {
|
2024-08-28 15:34:26 +00:00
|
|
|
pc += disassemble8080(buff, pc, json);
|
2024-08-19 15:41:54 +00:00
|
|
|
}
|
|
|
|
free(buff);
|
2024-08-28 15:34:26 +00:00
|
|
|
cJSON_Delete(json); // basically free(json)
|
2024-08-19 15:41:54 +00:00
|
|
|
return 0;
|
|
|
|
}
|