Skip to content

Instantly share code, notes, and snippets.

@gus33000
Forked from sunflower2333/Disassembler.c
Last active May 2, 2024 15:52
Show Gist options
  • Select an option

  • Save gus33000/329d6c830b1d200d69de4f5c21140977 to your computer and use it in GitHub Desktop.

Select an option

Save gus33000/329d6c830b1d200d69de4f5c21140977 to your computer and use it in GitHub Desktop.
ProtocolsFinder
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
//#define DEBUG
uint32_t swap_uint32(uint32_t x) {
return ((x >> 24) |
((x & 0x00FF0000) >> 8) |
((x & 0x0000FF00) << 8) |
(x << 24));
}
#define IMAGE_SIZEOF_SHORT_NAME 8
typedef struct _IMAGE_SECTION_HEADER {
uint8_t Name[IMAGE_SIZEOF_SHORT_NAME];
union {
uint32_t PhysicalAddress;
uint32_t VirtualSize;
} Misc;
uint32_t VirtualAddress;
uint32_t SizeOfRawData;
uint32_t PointerToRawData;
uint32_t PointerToRelocations;
uint32_t PointerToLinenumbers;
uint16_t NumberOfRelocations;
uint16_t NumberOfLinenumbers;
uint32_t Characteristics;
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
typedef struct arm64_adrp{
// instruction instructure
uint8_t Rd:5;
uint32_t immhi:19;
uint8_t op2:5;
uint8_t immlo:2;
uint8_t op1:1;
// extra data
uint32_t imm;
uint64_t pc;
uint64_t RdAfterExecution;
}__attribute__((packed, aligned(1))) Arm64Adrp;
typedef struct arm64_add{
// instruction instructure
uint16_t Rd:5;
uint16_t Rn:5;
uint16_t imm12:12;
uint8_t sh:1;
uint16_t op2:6;
uint8_t s:1;
uint8_t op1:1;
uint8_t sf:1;
// extra data
uint32_t imm;
uint64_t pc;
uint64_t RdAfterExecution;
}__attribute__((packed, aligned(1))) Arm64Add;
typedef union Ins{
Arm64Adrp adrp;
Arm64Add add;
uint32_t val;
}INST;
#define UINT8 uint8_t
#define UINT16 uint16_t
#define UINT32 uint32_t
#define UINT64 uint64_t
//*****************************************************//
//EFI_IMAGE_DATA_DIRECTORY
//*****************************************************//
typedef struct {
UINT32 VirtualAddress;
UINT32 Size;
} EFI_IMAGE_DATA_DIRECTORY;
#define EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC 0
#define EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG 1
#define EFI_TE_IMAGE_HEADER_SIGNATURE 0x5A56 // "VZ"
typedef struct {
UINT16 Signature;
UINT16 Machine;
UINT8 NumberOfSections;
UINT8 Subsystem;
UINT16 StrippedSize;
UINT32 AddressOfEntryPoint;
UINT32 BaseOfCode;
UINT64 ImageBase;
EFI_IMAGE_DATA_DIRECTORY DataDirectory[2];
} EFI_TE_IMAGE_HEADER;
//
// Store some file information and file buffer.
//
typedef struct {
union {
uint8_t *fileBuffer;
EFI_TE_IMAGE_HEADER *teHeader;
};
uint8_t *programBuffer;
size_t teSize;
size_t fileSize;
const char *filePath;
} FileContent, *pFileContent;
/**
* Read File buffer based on given fileContent.
*
* @param fileContent provide filePath, will also set fileBuffer in it.
* @return Buffer read from file.
*/
uint8_t *read_file_content(FileContent *fileContent) {
if (fileContent->fileBuffer == NULL)
return NULL;
FILE *pFile = fopen(fileContent->filePath, "rb");
if (pFile == NULL)
return NULL;
fread(fileContent->fileBuffer, fileContent->fileSize, 1, pFile);
// Reach end of header
fileContent->programBuffer = fileContent->fileBuffer + sizeof(EFI_TE_IMAGE_HEADER) + sizeof(IMAGE_SECTION_HEADER)*fileContent->teHeader->NumberOfSections;
// Jump over ALIGN
while(*(uint32_t*)fileContent->programBuffer == 0x0)
fileContent->programBuffer+=4;
// Print Header infomation
printf( "============Header Info============\n"
"Signature 0x%08X\n"
"Machine 0x%08X\n"
"NumberOfSections 0x%08X\n"
"Subsystem 0x%08X\n"
"StrippedSize 0x%08X\n"
"AddressOfEntryPoint 0x%08X\n"
"BaseOfCode 0x%08X\n"
"ImageBase 0x%08lX\n"
"Program offset: 0x%08lX\n",
fileContent->teHeader->Signature,
fileContent->teHeader->Machine,
fileContent->teHeader->NumberOfSections,
fileContent->teHeader->Subsystem,
fileContent->teHeader->StrippedSize,
fileContent->teHeader->AddressOfEntryPoint,
fileContent->teHeader->BaseOfCode,
fileContent->teHeader->ImageBase,
fileContent->programBuffer-fileContent->fileBuffer
);
fclose(pFile);
return (uint8_t*)fileContent->fileBuffer;
}
/**
* Get file size based on given fileContent.
*
* @param fileContent provide filePath, will also set fileSize in it.
* @retval 0 File does not exist.
* @retval size_t File size
*
*/
size_t get_file_size(FileContent *fileContent) {
FILE *pFile = fopen(fileContent->filePath, "r");
if (pFile == NULL) {
printf("Error: %s not found\n", fileContent->filePath);
return 0;
}
fseek(pFile, 0, SEEK_END);
size_t len = ftell(pFile);
fclose(pFile);
fileContent->fileSize = len;
fileContent->teSize = len - sizeof(EFI_TE_IMAGE_HEADER);
return len;
}
/**
* @param fileContent provided buffer and buffer size.
* @param KeyGuid is the buffer need to find in buffer.
* @retval offset of guid in buffer.
**/
int find_guid_in_buffer(FileContent *fileContent, uint8_t *KeyGuid) {
for (size_t i = 0; i <= fileContent->teSize - 16; i++) {
if (memcmp(fileContent->programBuffer+i, KeyGuid, 16) == 0) {
return i;
}
}
return -EINVAL; // Not found
}
bool validate_adrp(INST *inst){
return (inst->adrp.op1 == 1 && inst->adrp.op2 == 16 && inst->adrp.Rd <=30);
}
bool validate_add(INST *inst){
return (inst->add.op1==0 && inst->add.s==0 && inst->add.op2==34);
}
int parse_adrp(INST *inst, uint32_t offset){
// Store immediate number
inst->adrp.imm = (inst->adrp.immhi << 2 | inst->adrp.immlo) << 12;
// Store PC and Register(after executing adrp) address
inst->adrp.pc = offset;
inst->adrp.RdAfterExecution = ((inst->adrp.pc>>12)<<12) + inst->adrp.imm;
#ifdef DEBUG
printf("ins: %X, op1: %d, op2: %d, immlo: %d, immhi: %d, Rd: %d, imm: 0x%X, RdAfterExecution: 0x%X\n", inst->val, inst->adrp.op1, inst->adrp.op2, inst->adrp.immlo,
inst->adrp.immhi, inst->adrp.Rd, inst->adrp.imm, inst->adrp.RdAfterExecution);
#endif
};
uint64_t find_protocol_scheduler(FileContent *Binary, uint8_t *KeyGuid){
// Find Guid Offset
uint32_t guid_offset = find_guid_in_buffer(Binary, KeyGuid);
if(guid_offset == -1)
return -EINVAL;
printf("Found guid at 0x%X\n", guid_offset);
printf("Size of struct Header: 0x%lX\n", sizeof(EFI_TE_IMAGE_HEADER));
// Find all ADRP function
for(uint32_t offset=0; offset < Binary->fileSize-8-sizeof(EFI_TE_IMAGE_HEADER); offset+=4){
INST instruction = {.val=*(uint32_t*)(Binary->fileBuffer+offset)};
// Check adrp
if(validate_adrp(&instruction)){
// Found a valid adrp instruction
parse_adrp(&instruction, offset);
// Check if there is an add function at next next instruction
INST nnInst = {.val=*(uint32_t*)(Binary->fileBuffer+offset+8)};
if(validate_add(&nnInst)){
#ifdef DEBUG
printf("add ins: %X, sf: %d, op1: %d, S: %d, op2: %d, sh: %d, imm12: %X, Rn: %d, Rd: %d\n", nnInst.val, nnInst.add.sf,
nnInst.add.op1, nnInst.add.s, nnInst.add.op2, nnInst.add.sh, nnInst.add.imm12,
nnInst.add.Rn, nnInst.add.Rd);
#endif
// Get target address
uint32_t target_address = instruction.adrp.RdAfterExecution + nnInst.add.imm12;
#ifdef DEBUG
printf("RdAfterExecution: 0x%X, imm12: 0x%X, target_address: 0x%X\n", instruction.adrp.RdAfterExecution, nnInst.add.imm12, target_address);
#endif
if(target_address == guid_offset){
printf("Found instruction 0x%lX load GUID address.\n", instruction.adrp.pc);
// Get the adrp instruction before current adrp.
INST bInst = {.val=*(uint32_t*)(Binary->fileBuffer+offset-4)};
// Check adrp
if(validate_adrp(&bInst)){
// Found a valid adrp instruction
parse_adrp(&bInst, offset);
// Check Add
INST nInst = {.val=*(uint32_t*)(Binary->fileBuffer+offset+4)};
if(validate_add(&nInst)){
// Get target address
return bInst.adrp.RdAfterExecution + nInst.add.imm12 + Binary->teHeader->BaseOfCode + Binary->teHeader->ImageBase;
}
}
}
}
}
}
return 0;
}
uint64_t find_protocol_xbldt(FileContent *Binary, uint8_t *KeyGuid){
// Find Guid Offset
uint32_t guid_offset = find_guid_in_buffer(Binary, KeyGuid);
if(guid_offset == -1)
return -EINVAL;
printf("Found guid at 0x%X\n", guid_offset);
printf("Size of struct Header: 0x%lX\n", sizeof(EFI_TE_IMAGE_HEADER));
// Find all ADRP function
for(uint32_t offset=0; offset < Binary->fileSize-8-sizeof(EFI_TE_IMAGE_HEADER); offset+=4){
INST instruction = {.val=*(uint32_t*)(Binary->fileBuffer+offset)};
// Check adrp
if(validate_adrp(&instruction)){
// Found a valid adrp instruction
parse_adrp(&instruction, offset);
// Check if there is an add function at next instruction
INST nInst = {.val=*(uint32_t*)(Binary->fileBuffer+offset+4)};
if(validate_add(&nInst)){
#ifdef DEBUG
printf("add ins: %X, sf: %d, op1: %d, S: %d, op2: %d, sh: %d, imm12: %X, Rn: %d, Rd: %d\n", nnInst.val, nnInst.add.sf,
nnInst.add.op1, nnInst.add.s, nnInst.add.op2, nnInst.add.sh, nnInst.add.imm12,
nnInst.add.Rn, nnInst.add.Rd);
#endif
// Get target address
uint32_t target_address = instruction.adrp.RdAfterExecution + nInst.add.imm12;
#ifdef DEBUG
printf("RdAfterExecution: 0x%X, imm12: 0x%X, target_address: 0x%X\n", instruction.adrp.RdAfterExecution, nnInst.add.imm12, target_address);
#endif
if(target_address == guid_offset){
printf("Found instruction 0x%lX load GUID address.\n", instruction.adrp.pc);
// Get the adrp instruction at 3 instructions before current one.
INST bbbInst = {.val=*(uint32_t*)(Binary->fileBuffer+offset-12)};
// Check adrp
if(validate_adrp(&bbbInst)){
// Found a valid adrp instruction
parse_adrp(&bbbInst, offset);
// Check Add
INST bbInst = {.val=*(uint32_t*)(Binary->fileBuffer+offset-8)};
if(validate_add(&bbInst)){
// Get target address
return bbbInst.adrp.RdAfterExecution + bbInst.add.imm12 + Binary->teHeader->BaseOfCode + Binary->teHeader->ImageBase;
}
}
}
}
}
}
return 0;
}
uint64_t find_protocol_fvdecompress(FileContent *Binary, uint8_t *KeyGuid){
// Find Guid Offset
uint32_t guid_offset = find_guid_in_buffer(Binary, KeyGuid);
if(guid_offset == -1)
return -EINVAL;
printf("Found guid at 0x%X\n", guid_offset);
printf("Size of struct Header: 0x%lX\n", sizeof(EFI_TE_IMAGE_HEADER));
// Find all ADRP function
for(uint32_t offset=0; offset < Binary->fileSize-8-sizeof(EFI_TE_IMAGE_HEADER); offset+=4){
INST instruction = {.val=*(uint32_t*)(Binary->fileBuffer+offset)};
// Check adrp
if(validate_adrp(&instruction)){
// Found a valid adrp instruction
parse_adrp(&instruction, offset);
// Check if there is an add function at next next instruction
INST nnInst = {.val=*(uint32_t*)(Binary->fileBuffer+offset+8)};
if(validate_add(&nnInst)){
#ifdef DEBUG
printf("add ins: %X, sf: %d, op1: %d, S: %d, op2: %d, sh: %d, imm12: %X, Rn: %d, Rd: %d\n", nnInst.val, nnInst.add.sf,
nnInst.add.op1, nnInst.add.s, nnInst.add.op2, nnInst.add.sh, nnInst.add.imm12,
nnInst.add.Rn, nnInst.add.Rd);
#endif
// Get target address
uint32_t target_address = instruction.adrp.RdAfterExecution + nnInst.add.imm12;
#ifdef DEBUG
printf("RdAfterExecution: 0x%X, imm12: 0x%X, target_address: 0x%X\n", instruction.adrp.RdAfterExecution, nnInst.add.imm12, target_address);
#endif
if(target_address == guid_offset){
printf("Found instruction 0x%lX load GUID address.\n", instruction.adrp.pc);
// Get the adrp instruction before current adrp.
INST bInst = {.val=*(uint32_t*)(Binary->fileBuffer+offset-4)};
// Check adrp
if(validate_adrp(&bInst)){
// Found a valid adrp instruction
parse_adrp(&bInst, offset);
// Check Add
INST nInst = {.val=*(uint32_t*)(Binary->fileBuffer+offset+4)};
if(validate_add(&nInst)){
// Get target address
return bInst.adrp.RdAfterExecution + nInst.add.imm12 + Binary->teHeader->BaseOfCode + Binary->teHeader->ImageBase;
}
}
}
}
}
}
return 0;
}
int main(int argc, char *argv[]){
// Get binary file buffer.
FileContent Binary = {.filePath = argv[1]};
if (!get_file_size(&Binary))
return -EINVAL;
// Read file into buffer.
Binary.fileBuffer = malloc(Binary.fileSize);
read_file_content(&Binary);
// Search our GUID, get address.
uint8_t SchedulerGuid[] = { 0x8D, 0xBD, 0xC2, 0x8E,
0xD7, 0x56, 0xEF, 0x49,
0x87, 0x96, 0x63, 0x17,
0x78, 0xF8, 0xEB, 0xF8
};
uint8_t XBLDTGuid[] = { 0xE8, 0xE1, 0x06, 0x3A,
0xF6, 0x61, 0xEB, 0x11,
0xBB, 0xED, 0x4B, 0x47,
0x6E, 0x2F, 0xF6, 0xA7
};
uint8_t FvDecompressGuid[] = { 0x3D, 0xD9, 0xDB, 0x12,
0x2A, 0x40, 0x6E, 0x41,
0xEC, 0x20, 0x5F, 0x80,
0xCF, 0x5F, 0x7F, 0xE7
};
printf( "\n============Search Log============\n");
uint64_t scheduler_addr = find_protocol_scheduler(&Binary, SchedulerGuid);
uint64_t xbldt_addr = find_protocol_xbldt(&Binary, XBLDTGuid);
uint64_t fvdecompress_addr = find_protocol_fvdecompress(&Binary, FvDecompressGuid);
if(scheduler_addr)
printf("\033[1;31mSchduler Protocol Address:\033[0m \033[38;5;214m0x%lX\033[0m\n", scheduler_addr);
else
printf("\033[1;31mSchduler Protocol Not Found\033[0m\n");
if(xbldt_addr)
printf("\033[1;31mXBLDT protocol Address:\033[0m \033[38;5;214m0x%lX\033[0m\n", xbldt_addr);
else
printf("\033[1;31mXBLDT Protocol Not Found\033[0m\n");
if(fvdecompress_addr)
printf("\033[1;31mFVDecompress protocol Address:\033[0m \033[38;5;214m0x%lX\033[0m\n", fvdecompress_addr);
else
printf("\033[1;31mFVDecompress Protocol Not Found\033[0m\n");
// Free buffers.
free(Binary.fileBuffer);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment