-
-
Save gus33000/329d6c830b1d200d69de4f5c21140977 to your computer and use it in GitHub Desktop.
ProtocolsFinder
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #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