Skip to content

Instantly share code, notes, and snippets.

@sunflower2333
Last active August 24, 2024 08:29
Show Gist options
  • Select an option

  • Save sunflower2333/703d7af2523a351357ee0ff91fad4cbf to your computer and use it in GitHub Desktop.

Select an option

Save sunflower2333/703d7af2523a351357ee0ff91fad4cbf 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;
#pragma pack(1)
typedef struct arm64_adrp {
// instruction instructure
uint32_t Rd : 5;
uint32_t immhi : 19;
uint32_t op2 : 5;
uint32_t immlo : 2;
uint32_t op1 : 1;
// extra data
uint32_t imm;
uint64_t pc;
uint64_t RdAfterExecution;
}Arm64Adrp;
#pragma pack()
#pragma pack(1)
typedef struct arm64_add {
// instruction instructure
uint32_t Rd : 5;
uint32_t Rn : 5;
uint32_t imm12 : 12;
uint32_t sh : 1;
uint32_t op2 : 6;
uint32_t s : 1;
uint32_t op1 : 1;
uint32_t sf : 1;
// extra data
uint32_t imm;
uint64_t pc;
uint64_t RdAfterExecution;
} Arm64Add;
#pragma pack()
#pragma pack(1)
typedef union Ins {
Arm64Adrp adrp;
Arm64Add add;
uint32_t val;
}INST;
#pragma pack()
#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) };
//printf("instruction 0x%llx", instruction.val);
// 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", nInst.val, nInst.add.sf,
nInst.add.op1, nInst.add.s, nInst.add.op2, nInst.add.sh, nInst.add.imm12,
nInst.add.Rn, nInst.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, nInst.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;
}
int main(int argc, char* argv[]) {
// Check arg
if (argc < 2) {
printf("\n Usage: ./Disassembler XBLCore.te\n\n");
return -EINVAL;
}
// 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
};
printf("Sizeof %lld\n", sizeof(INST));
printf("Sizeof %lld\n", sizeof(Arm64Add));
printf("Sizeof %lld\n", sizeof(Arm64Adrp));
printf("\n============Search Log============\n");
uint64_t scheduler_addr = find_protocol_scheduler(&Binary, SchedulerGuid);
uint64_t xbldt_addr = find_protocol_xbldt(&Binary, XBLDTGuid);
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");
// Free buffers.
free(Binary.fileBuffer);
return 0;
}
@sunflower2333
Copy link
Author

How to use

  • Get XBLCore.te from your UEFI for XBL with 7z or UEFIReader.
  • Compile this tool in linux
    • gcc Disassembler.c
  • Run the tool
    $ ./a.out XBLCore.te
    ============Header Info============
    Signature              0x00005A56
    Machine                0x0000AA64
    NumberOfSections       0x00000003
    Subsystem              0x0000000B
    StrippedSize           0x00000F60
    AddressOfEntryPoint    0x0000CC68
    BaseOfCode             0x00001000
    ImageBase              0xA7001000
    Program offset:        0x000000C8
    
    ============Search Log============
    Found guid at 0x392A0
    Size of struct Header: 0x28
    Found instruction 0x276A4 load GUID address.
    Found guid at 0x39290
    Size of struct Header: 0x28
    Found instruction 0x12810 load GUID address.
    Schduler Protocol Address: 0xA703B918
    XBLDT protocol Address: 0xA703B0C8
    

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment