diff --git a/src/zcoff/src/COFF_Loader.c b/src/zcoff/src/COFF_Loader.c deleted file mode 100644 index fc9af3b..0000000 --- a/src/zcoff/src/COFF_Loader.c +++ /dev/null @@ -1,407 +0,0 @@ -#include -#include -#include "coff_definitions.h" -#include "beacon_compatibility.h" -#include "COFF_Loader.h" - - -#pragma region general functions -PBYTE mem_alloc(SIZE_T size, UINT32 flags, UINT32 protection) { - PBYTE ret; - ret = (PBYTE)VirtualAlloc(NULL, size, flags, protection); - return ret; -} -PBYTE coff_read_file(PCHAR filepath) { - HANDLE hFile = NULL; - UINT32 FileSize; - PBYTE buffer = NULL; - - hFile = CreateFileA(filepath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); - if (!hFile) - return NULL; - - FileSize = GetFileSize(hFile, NULL); - if (FileSize == INVALID_FILE_SIZE) - goto cleanup; - - buffer = mem_alloc(FileSize, MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE); - if (!buffer) - goto cleanup; - - if (!ReadFile(hFile, buffer, FileSize, NULL, NULL)) - DEBUG_PRINT("Couldn't read input file! %d\n", GetLastError()); - - if (VirtualProtect(buffer, FileSize, PAGE_READONLY, NULL)) - DEBUG_PRINT("Couldn't change protection to PAGE_READONLY: %d\n", GetLastError); - -cleanup: - CloseHandle(hFile); - return buffer; -} -PUCHAR unpack_arguments(PCHAR arguments, size_t* outlen) { - PUCHAR retval = NULL; - CHAR byteval[2] = { 0 }; - - if (!arguments) - RETURN_NULL_ERROR("No arguments to parse"); - - size_t value_len = strlen((LPCSTR)arguments); - - if (value_len % 2 != 0) - RETURN_NULL_ERROR("The hexlified string isn't valid\n"); - - - retval = mem_alloc(value_len + 1, MEM_COMMIT, PAGE_READWRITE); - if (!retval) - RETURN_NULL_ERROR("couldn't allocate memory for args"); - - /* args are in hex, unpackign */ - for (size_t i = 0; i < value_len; i += 2) { - memcpy(byteval, arguments + i, 2); - CHAR character = strtol(byteval, NULL, 16); - retval[i / 2] = character; - } - - *outlen = value_len / 2; - return retval; -} -LPVOID process_external_symbol(PCHAR symbolstring) { - LPVOID functionaddress = NULL; - CHAR localcopy[1024] = { 0 }; - PCHAR locallib = NULL; - PCHAR localfunc = NULL; - HMODULE llHandle = NULL; - PCHAR therest = NULL; - - - CHAR prefix[] = "__imp_"; - CHAR prefix_beacon[] = "__imp_Beacon"; - CHAR prefix_towidechar[] = "__imp_toWideChar"; - size_t prefix_len = strlen(prefix); - - /* the symbol name doesn't conform to our naming convention */ - if (strncmp(symbolstring, prefix, strlen(prefix))) - RETURN_NULL_ERROR("not conforming to our naming convention\n"); - - - /* check if it's an internal beacon function */ - if (strncmp(symbolstring, prefix_beacon, strlen(prefix_beacon)) == 0 - || strncmp(symbolstring, prefix_towidechar, strlen(prefix_towidechar)) == 0) { - - localfunc = symbolstring + prefix_len; - - for (int i = 0; i < 25; i++) { - if (InternalFunctions[i][0] != NULL) { - if (strcmp(localfunc, (PCHAR)(InternalFunctions[i][0])) == 0) { - functionaddress = (PCHAR)InternalFunctions[i][1]; - return functionaddress; - } - } - } - } - - /* if we are here, it is an external function */ - strcpy_s(localcopy, _countof(localcopy), symbolstring); - locallib = strtok_s(localcopy + prefix_len, "$@", &therest); - localfunc = strtok_s(therest, "$@", &therest); - if (!localfunc || !locallib) - RETURN_NULL_ERROR("couldn't extract external function name, %s\n", symbolstring) - - llHandle = LoadLibraryA(locallib); - if (llHandle) { - functionaddress = GetProcAddress(llHandle, localfunc); - if (!functionaddress) - RETURN_NULL_ERROR("No func %s in %s\n", localfunc, locallib); - // FreeLibrary(llHandle); // we can't free the library until execution is done. TODO: keep a list of loaded dll per bof to unload after execution - } - else { - RETURN_NULL_ERROR("couldn't load library %s\n", locallib) - } - return functionaddress; -} -#pragma endregion - -#pragma region relocation functions -UINT32 read32le(const PUINT8 p) -{ - /* The one true way, see - * https://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html */ - return ((UINT32)p[0] << 0) | - ((UINT32)p[1] << 8) | - ((UINT32)p[2] << 16) | - ((UINT32)p[3] << 24); -} -VOID write32le(PUINT8 dst, UINT32 x) -{ - dst[0] = (UINT8)(x >> 0); - dst[1] = (UINT8)(x >> 8); - dst[2] = (UINT8)(x >> 16); - dst[3] = (UINT8)(x >> 24); -} -VOID add32(PUINT8 P, UINT32 V) { write32le(P, read32le(P) + V); } -VOID coff_apply_relocations(PUINT32 P, PBYTE S, UINT16 Type, UINT32 SymOffset) { - - switch (Type) - { - case IMAGE_REL_AMD64_REL32: add32(P, S + SymOffset - (PBYTE)P - 4); break; - case IMAGE_REL_AMD64_ADDR32NB: add32(P, S - (PBYTE)P - 4); break; - case IMAGE_REL_AMD64_ADDR64:*P = (*P + S); break; -// working alternatives -// case IMAGE_REL_AMD64_REL32: *P += (S + SymOffset - P - 4); break; -// case IMAGE_REL_AMD64_ADDR32NB: *P = (S - P - 4); break; -// case IMAGE_REL_AMD64_ADDR64: *P = (*P + S); break; - default: - DEBUG_PRINT("NO CODE TO RELOCATE TYPE: %d\n", Type); - break; - } - -} -#pragma endregion - -#pragma region coff helper functions -SymbolTableEntry* coff_get_symbol_table(PBYTE pImageBase) { - if (!pImageBase) - return NULL; - - return (SymbolTableEntry*)(pImageBase + ((FileHeader*)pImageBase)->PointerToSymbolTable); -} -UINT32 coff_get_ext_function_space(PBYTE pImageBase) { - UINT32 ret = 0; - SymbolTableEntry* pSymbolTable; - RelocationTableEntry* reloc; - SectionHeader* pTextSectionHeader; - if (!pImageBase) - return 0; //TODO: This is not optimal because it may lead to crashes if external functions exist but NULL is passed - - pTextSectionHeader = coff_get_text_section_header(pImageBase); - pSymbolTable = coff_get_symbol_table(pImageBase); - reloc = (RelocationTableEntry*)(pImageBase + pTextSectionHeader->PointerToRelocations); - if (!pTextSectionHeader || !pSymbolTable) - RETURN_ERROR("couldn't get symbol table or text section"); - - for (int i = 0; i < pTextSectionHeader->NumberOfRelocations; i++) - { - SymbolTableEntry* sym = pSymbolTable + reloc->SymbolTableIndex; - /* The External storage class may include functions in the .text section as well (internal functions). - To ensure that only external functions are included, a check for the section number is added. - A section number of 0 == UNDEF section, which is the case for external functions. - */ - if (sym->StorageClass == IMAGE_SYM_CLASS_EXTERNAL && sym->SectionNumber == 0) - { - ret++; - } - reloc++; - } - return ret * sizeof(PBYTE); -} -BOOL coff_execute_entry(coff_object coff, PCHAR func, PUCHAR args, UINT32 argSize) { - VOID(*foo)(PCHAR in, UINT32 datalen) = NULL; - - if (!func || !coff.pImageBase) - RETURN_ERROR("no entry provided"); - - for (UINT32 counter = 0; counter < ((FileHeader*)coff.pImageBase)->NumberOfSymbols; counter++) - { - if (strcmp(coff.symbol_table[counter].first.Name, func) == 0) { - // foo = (PCHAR)coff.pTextSectionRawData; to my surprise, this won't work! It appears that go isn't always at the beginning of the .text section! - foo = (PCHAR)(coff.pTextSectionRawData + coff.symbol_table[counter].Value); - DEBUG_PRINT("Trying to run: %p\n", foo); - } - } - - if (!foo) - RETURN_ERROR("couldn't find entry point"); - - foo(args, argSize); - return TRUE; -} -SectionHeader* coff_get_text_section_header(PBYTE pImageBase) { - - FileHeader* pFileHeader; - - if (!pImageBase) - return NULL; - - pFileHeader = (FileHeader*)pImageBase; - - for (int i = 0; i < pFileHeader->NumberOfSections; i++) - { - SectionHeader* pSectionHeader = (SectionHeader*)(pImageBase + sizeof(FileHeader) + (sizeof(SectionHeader) * i)); - if (strstr(pSectionHeader->Name, ".text")) - return pSectionHeader; - } - - return NULL; -} -BOOL coff_extract_text_section(PBYTE pImageBase, coff_object* coff) { - - UINT32 sizeOfData; - SectionHeader* pTextSectionHeader; - - if (!coff || !pImageBase) - RETURN_ERROR("invalid args"); - - coff->pImageBase = pImageBase; - coff->symbol_table = coff_get_symbol_table(pImageBase); - - pTextSectionHeader = coff_get_text_section_header(pImageBase); - if (!pTextSectionHeader) - RETURN_ERROR("pTextHeader is null"); - - coff->pTextSectionHeader = pTextSectionHeader; - sizeOfData = pTextSectionHeader->SizeOfRawData + coff_get_ext_function_space(pImageBase); - coff->pTextSectionRawData = mem_alloc(sizeOfData, MEM_COMMIT | MEM_TOP_DOWN, PAGE_EXECUTE_READWRITE); - if (!coff->pTextSectionRawData) - RETURN_ERROR("couldn't allocate new .text section"); - - memcpy(coff->pTextSectionRawData, - pImageBase + pTextSectionHeader->PointerToRawData, - pTextSectionHeader->SizeOfRawData); - - return TRUE; -} -PBYTE coff_get_section_raw_data_by_index(PBYTE pImageBase, UINT32 index) { - SectionHeader* pSectionHeader; - - if (!pImageBase) - return NULL; - - pSectionHeader = (SectionHeader*)(pImageBase + sizeof(FileHeader) + (sizeof(SectionHeader) * index)); - - return pImageBase + pSectionHeader->PointerToRawData; -} -BOOL coff_relocate_text_section(coff_object coff) { - - UINT32 functionMappingCount = 0; - PBYTE current_section_ptr; - RelocationTableEntry* Reloc; - - - current_section_ptr = coff.pTextSectionRawData; - if (!current_section_ptr) - RETURN_ERROR(".text is null"); - - Reloc = (RelocationTableEntry*)(coff.pImageBase + coff.pTextSectionHeader->PointerToRelocations); - - for (int ireloc = 0; ireloc < coff.pTextSectionHeader->NumberOfRelocations; ireloc++) - { - UINT16 TargetSectionIndex; - SymbolTableEntry* sym; - BOOL isExternal, isInternal; - PUINT32 P; /* Location to patch */ - - TargetSectionIndex = coff.symbol_table[Reloc->SymbolTableIndex].SectionNumber - 1; - sym = coff.symbol_table + Reloc->SymbolTableIndex; - isExternal = (sym->StorageClass == IMAGE_SYM_CLASS_EXTERNAL && sym->SectionNumber == 0); - isInternal = (sym->StorageClass == IMAGE_SYM_CLASS_EXTERNAL && sym->SectionNumber != 0); - - - P = (PUINT32)( - current_section_ptr - + Reloc->VirtualAddress - - coff.pTextSectionHeader->VirtualAddress); - - if (isExternal) - { - PUINT64 pFunction; - UINT32 StringTableOffset = sym->first.value[1]; - PCHAR function_full_name = ((PCHAR)(coff.symbol_table + ((FileHeader*)coff.pImageBase)->NumberOfSymbols) + StringTableOffset); - PUINT64 func_addr2 = (PUINT64)(current_section_ptr + coff.pTextSectionHeader->SizeOfRawData); - - pFunction = process_external_symbol(function_full_name); - - if (pFunction) - { - /* copy the address of the ext. function into the region right after the .text section */ - *(func_addr2 + (functionMappingCount)) = (UINT64)pFunction; - - /* calculate the difference between P and the copied ext. func addr */ - UINT32 v = (UINT32)((UINT32)(func_addr2 + (functionMappingCount)) - (UINT32)(P)-4); - - /* copy the difference to P */ - *(PINT32)P = v; - functionMappingCount += 1; - } - else { - RETURN_ERROR("couldn't resolve function"); - } - } - else { - /* not an external function, could be either internal or data - if it's an internal function, then the target section should be the text - section. Otherwise, the target section should be whatever section the data - is in. - - The reason that .text section is having a special treatment here is because - we re-allocated it to another region in memory to make it executable. If we - use coff_get_section_by_index for the text section, we will get a pointer to - the original text_section, which is not in an executable memory region. - - This can be simplified by allocating executable memory for the entire coff. I wasn't sure about the - detection complications in an executable memory for the entire coff so decided to stick to only the - .text section. Maybe in future versions I'll simplifythis by having the entire coff in an - executable region. - - */ - PBYTE S = coff_get_section_raw_data_by_index(coff.pImageBase, TargetSectionIndex); - if (!S) - RETURN_ERROR("target section is null"); - - /* VS compiler won't patch relative addresses of internal functions for us so we have to do it ourselves */ - if (isInternal) - S = coff.pTextSectionRawData; - - coff_apply_relocations(P, S, Reloc->Type, sym->Value); - } - Reloc++; - } - return TRUE; -} -#pragma endregion - -void main(int argc, char* argv[]) { - - PBYTE coff_data = NULL; - coff_object coff; - PCHAR arguments = NULL; - size_t arg_size = 0; - - if (argc < 2) { - printf("not enough args...\nUsage: %s [path_to_obj_file] ", argv[0]); - return; - } - - coff_data = coff_read_file(argv[1]); - if (!coff_data) - return; - - if(argv[2]) - arguments = unpack_arguments(argv[2], &arg_size); - - if (!coff_extract_text_section(coff_data, &coff)) - goto cleanup; - - - if (!coff_relocate_text_section(coff)) - goto cleanup; - - - if (!coff_execute_entry(coff, "go", arguments, (UINT32)arg_size)) - goto cleanup; - - PCHAR outdata = BeaconGetOutputData(NULL); - if (outdata != NULL) { - printf("\nOutdata Below:\n\n%s\n", outdata); - } - -cleanup: - if(coff_data) - VirtualFree(coff_data, 0, MEM_RELEASE); - if (coff.pTextSectionRawData) - VirtualFree(coff.pTextSectionRawData, 0, MEM_RELEASE); - if (arguments) - VirtualFree(arguments, 0, MEM_RELEASE); -} - - - diff --git a/src/zcoff/src/COFF_Loader.h b/src/zcoff/src/COFF_Loader.h deleted file mode 100644 index 0364a8f..0000000 --- a/src/zcoff/src/COFF_Loader.h +++ /dev/null @@ -1,114 +0,0 @@ -#pragma once -#include "coff_definitions.h" - -typedef struct { - PBYTE pImageBase; - SectionHeader* pTextSectionHeader; - PBYTE pTextSectionRawData; - SymbolTableEntry* symbol_table; -} coff_object; - -#pragma region error_handling -#define RETURN_ERROR(x, ...) { printf(x, ##__VA_ARGS__); return FALSE; } -#define RETURN_NULL_ERROR(x, ...) { printf(x, ##__VA_ARGS__); return NULL;} -#define DEBUG_PRINT(x, ...) printf(x, ##__VA_ARGS__) -#pragma endregion - -/// -/// Reads a coff from a specified path, no parsing is done in this function -/// -/// path to coff object location -/// a read/write pointer to in-memory coff object -PBYTE coff_read_file(PCHAR filepath); - -/// -/// Unpack packed arguments for CS compatibility -/// -/// hex string representing args -/// on success, returns the total size of the args -/// unpacked arguments -PUCHAR unpack_arguments(PCHAR arguments, size_t* outlen); - -/// -/// Finds the address of an external symbol that was created using lib$func naming convention -/// -/// a string containing a lib$func to be resolved -/// address to resolved external function -LPVOID process_external_symbol(PCHAR symbolstring); - -/// -/// generic function to apply coff relocations, some reloc types aren't implemented yet -/// -/// The location to be patched -/// The target section (section containing the actual data) -/// The type of the relocation -/// The symbol offset in the symbol table -VOID coff_apply_relocations(PUINT32 P, PBYTE S, UINT16 Type, UINT32 SymOffset); - -/// -/// Calculates the size needed to store pointers for external functions right after the text section -/// -/// pointer to coff image base -/// number of external symbols * sizeof(pointer) -UINT32 coff_get_ext_function_space(PBYTE pImageBase); - -/// -/// -/// -/// pointer to coff image base -/// pointer to the symbol table -SymbolTableEntry* coff_get_symbol_table(PBYTE pImageBase); - -/// -/// allocates memory using VirtualAlloc, can be easily modified to allocate using whatever method -/// -/// nr of bytes to be allocated -/// dwFlags from VirtualAlloc -/// dwProtection from VirtualAlloc -/// pointer to allocated memory -PBYTE mem_alloc(SIZE_T size, UINT32 flags, UINT32 protection); - -/// -/// Returns a pointer to the text section header. The text section header is a special case because we have -/// to use strstr() instead of strcmp() since MSVC will generate ".text$mn" while gcc will generate ".text". -/// We cannot use strstr() with every section header because MSVC will generate .rdata while gcc will generate -/// ".rdata$zzz", so I decided to have a separate function for .text section header -/// -/// pointer to coff image base -/// pointer to .text section header or null on failure -SectionHeader* coff_get_text_section_header(PBYTE pImageBase); - -/// -/// Extracts the .text section into a PAGE_EXECUTE_READWRITE memory region -/// -/// pointer to coff image base -/// a pointer to a coff_object struct to make my life easier -/// true if creation of new memory region succeeded, the new .text section will be stored in the coff_object -BOOL coff_extract_text_section(PBYTE pImageBase, coff_object* coff); - -/// -/// executes the coff entry function -/// -/// pointer to coff_object struct -/// pointer to the name of entry function, usually "go" -/// unpacked arguments -/// the size of the arguments -/// true if execution took place -BOOL coff_execute_entry(coff_object coff, PCHAR entry_name, PUCHAR args, UINT32 argSize); - -/// -/// Returns the raw data of the target section, which is identified by its index. Useful in relocations -/// where we know the index of the target section and have to access its data. -/// -/// pointer to coff image base -/// the index of the target section -/// a pointer to the beginning of the target section -PBYTE coff_get_section_raw_data_by_index(PBYTE pImageBase, UINT32 index); - -/// -/// Relocates the .text section of the coff file. The reason I chose to only relocate the .text sections -/// is because coff object execution only needs .text relocation. -/// -/// coff_object struct that is pre-filled by calling coff_extract_text_section first -/// true if relocations are performed without errors -BOOL coff_relocate_text_section(coff_object coff); \ No newline at end of file diff --git a/src/zcoff/src/README.md b/src/zcoff/src/README.md deleted file mode 100644 index 5dcd379..0000000 --- a/src/zcoff/src/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# COFFLoader2 - -This repo contains the source code of a Common Object File Format (COFF) loader, which is a rewrite of the research and implementation done by Kevin Haubris [@Kev169](https://twitter.com/kev169) on the [TrustedSec](https://www.trustedsec.com) GitHub repo [here](https://github.com/trustedsec/COFFLoader). Kevin also wrote an article about [building your own COFF loader](https://www.trustedsec.com/blog/coffloader-building-your-own-in-memory-loader-or-how-to-run-bofs/) - -Kevin did an excellent job in figuring out the relocations and implementing the beacon compatibility layer. This repo takes it a bit further in making the code prettier (beauty is in the eyes of the beholder anyway) and more readable. This repo includes more comments, extracted COFF-related code into re-usable functions, usage of MSVC-compliant functions, and fix issues with MSVC-compiled BOFs. Also, while the code is initially inspired by Kevin's work, the approach to the implementation of the relocations and memory allocation is different. - -### Why? - -Rewriting code is an excellent way to improve one's understanding of a topic. This was the main drive for rewriting the code. Another reason is that the original code is *probably* not meant for the VS toolchain, which is apparent in the fact that MSVC won't compile the code because of its insecure-function warnings and that the loader won't load MSVC-compiled BOFs. Since I like developing and compiling my BOFs with VS, this was another good reason to rewrite. Further, the original code seemed too complicated to my simple brain. For example, when I was trying to understand the original code, I found myself reading an `if statement` which is inside an `else if` that is inside another `else` which is inside a `for` loop that is inside another `for` loop. My brain couldn't keep up, the folks at TrustedSec are too smart for me haha. The code also lacked variables which made it quite challenging to read, so a rewrite seemed definitely worth the time and effort. Looking retrospectively, I am pretty happy about the decision! - -### What? - -The rewrite is focussed on the COFF-loading process only. I did not modify the beacon compatibility layer. A non-comprehensive list of changes - -- Re-implemented the relocations. The code now performs relocations on the .text section only, which is sufficient to get the COFF executed. However, applying the relocations to any other section should be straightforward with the new structure -- Improved readability by removing some nesting, using variables, and extracting some re-usable code into functions -- Used WIN32 API calls to open and read the file instead of the standard library functions -- Avoid double allocation for every section. The exception is .text section which is allocated again on PAGE_EXECUTE_READWRITE memory region. The other sections are located in PAGE_READONLY memory region. -- Removed fixed-size allocation for function mapping and check of whether the mapping is within 4GB limit by ensuring that the mapping will be right after the .text section. -- Added more error checking here and there - -### Todo - -While I didn't have any issues with testing, I'll maintain the original disclaimer. This code should be used for testing purposes, it needs further testing before using in production. - -What I'd like to do from here is using the loader over the network and take a deeper look into the beacon compatibility layer to see how this can be transformed into a COFF-based C2 and perhaps add x86 support. Much more can be added/modified but at one point I realized that the cycle of refactoring can continue forever and wanted to share a first version. Hopefully a blog post and more comments will follow. - -### Credits - -1. Huge thanks to Kevin [@Kev169](https://twitter.com/kev169) and the TrustedSec team for sharing their code. Going through the code and rewriting it made me realize the great effort and time invested in the original implementation. Great job Kevin and TrustedSec! -2. Patryk Czeczko ([@0xpat](https://twitter.com/0xPat)) wrote a nice blog article about COFF loaders [on his blog](https://0xpat.github.io/Malware_development_part_8/), was quite useful -3. While not directly related to the re-implementation, I liked the [BOF2Shellcode](https://medium.com/falconforce/bof2shellcode-a-tutorial-converting-a-stand-alone-bof-loader-into-shellcode-6369aa518548) article by Gijs Hollestelle ([@gijs_h](https://twitter.com/gijs_h)) and found it to be an exciting read. diff --git a/src/zcoff/src/beacon_compatibility.c b/src/zcoff/src/beacon_compatibility.c deleted file mode 100644 index da17a45..0000000 --- a/src/zcoff/src/beacon_compatibility.c +++ /dev/null @@ -1,350 +0,0 @@ -/* - * Cobalt Strike 4.X BOF compatibility layer - * ----------------------------------------- - * The whole point of these files are to allow beacon object files built for CS - * to run fine inside of other tools without recompiling. - * - * Built off of the beacon.h file provided to build for CS. - */ - - -#include -#include -#include -#include -#ifdef _WIN32 -#include - -#include "beacon_compatibility.h" - -#define DEFAULTPROCESSNAME "rundll32.exe" -#ifdef _WIN64 -#define X86PATH "SysWOW64" -#define X64PATH "System32" -#else -#define X86PATH "System32" -#define X64PATH "sysnative" -#endif - - - /* Data Parsing */ -unsigned char* InternalFunctions[25][2] = { - {(unsigned char*)"BeaconDataParse", (unsigned char*)BeaconDataParse}, - {(unsigned char*)"BeaconDataInt", (unsigned char*)BeaconDataInt}, - {(unsigned char*)"BeaconDataShort", (unsigned char*)BeaconDataShort}, - {(unsigned char*)"BeaconDataLength", (unsigned char*)BeaconDataLength}, - {(unsigned char*)"BeaconDataExtract", (unsigned char*)BeaconDataExtract}, - {(unsigned char*)"BeaconFormatAlloc", (unsigned char*)BeaconFormatAlloc}, - {(unsigned char*)"BeaconFormatReset", (unsigned char*)BeaconFormatReset}, - {(unsigned char*)"BeaconFormatFree", (unsigned char*)BeaconFormatFree}, - {(unsigned char*)"BeaconFormatAppend", (unsigned char*)BeaconFormatAppend}, - {(unsigned char*)"BeaconFormatPrintf", (unsigned char*)BeaconFormatPrintf}, - {(unsigned char*)"BeaconFormatToString", (unsigned char*)BeaconFormatToString}, - {(unsigned char*)"BeaconFormatInt", (unsigned char*)BeaconFormatInt}, - {(unsigned char*)"BeaconPrintf", (unsigned char*)BeaconPrintf}, - {(unsigned char*)"BeaconOutput", (unsigned char*)BeaconOutput}, - {(unsigned char*)"BeaconUseToken", (unsigned char*)BeaconUseToken}, - {(unsigned char*)"BeaconRevertToken", (unsigned char*)BeaconRevertToken}, - {(unsigned char*)"BeaconIsAdmin", (unsigned char*)BeaconIsAdmin}, - {(unsigned char*)"BeaconGetSpawnTo", (unsigned char*)BeaconGetSpawnTo}, - {(unsigned char*)"BeaconSpawnTemporaryProcess", (unsigned char*)BeaconSpawnTemporaryProcess}, - {(unsigned char*)"BeaconInjectProcess", (unsigned char*)BeaconInjectProcess}, - {(unsigned char*)"BeaconInjectTemporaryProcess", (unsigned char*)BeaconInjectTemporaryProcess}, - {(unsigned char*)"BeaconCleanupProcess", (unsigned char*)BeaconCleanupProcess}, - {(unsigned char*)"toWideChar", (unsigned char*)toWideChar} -}; - -uint32_t swap_endianess(uint32_t indata) { - uint32_t testint = 0xaabbccdd; - uint32_t outint = indata; - if (((unsigned char*)&testint)[0] == 0xdd) { - ((unsigned char*)&outint)[0] = ((unsigned char*)&indata)[3]; - ((unsigned char*)&outint)[1] = ((unsigned char*)&indata)[2]; - ((unsigned char*)&outint)[2] = ((unsigned char*)&indata)[1]; - ((unsigned char*)&outint)[3] = ((unsigned char*)&indata)[0]; - } - return outint; -} - -char* beacon_compatibility_output = NULL; -int beacon_compatibility_size = 0; -int beacon_compatibility_offset = 0; - -void BeaconDataParse(datap* parser, char* buffer, int size) { - if (parser == NULL) { - return; - } - parser->original = buffer; - parser->buffer = buffer; - parser->length = size - 4; - parser->size = size - 4; - parser->buffer += 4; - return; -} - -int BeaconDataInt(datap* parser) { - int32_t fourbyteint = 0; - if (parser->length < 4) { - return 0; - } - memcpy(&fourbyteint, parser->buffer, 4); - parser->buffer += 4; - parser->length -= 4; - return (int)fourbyteint; -} - -short BeaconDataShort(datap* parser) { - int16_t retvalue = 0; - if (parser->length < 2) { - return 0; - } - memcpy(&retvalue, parser->buffer, 2); - parser->buffer += 2; - parser->length -= 2; - return (short)retvalue; -} - -int BeaconDataLength(datap* parser) { - return parser->length; -} - -char* BeaconDataExtract(datap* parser, int* size) { - uint32_t length = 0; - char* outdata = NULL; - /*Length prefixed binary blob, going to assume uint32_t for this.*/ - if (parser->length < 4) { - return NULL; - } - memcpy(&length, parser->buffer, 4); - parser->buffer += 4; - - outdata = parser->buffer; - if (outdata == NULL) { - return NULL; - } - parser->length -= 4; - parser->length -= length; - parser->buffer += length; - if (size != NULL && outdata != NULL) { - *size = length; - } - return outdata; -} - -/* format API */ - -void BeaconFormatAlloc(formatp* format, int maxsz) { - if (format == NULL) { - return; - } - format->original = calloc(maxsz, 1); - format->buffer = format->original; - format->length = 0; - format->size = maxsz; - return; -} - -void BeaconFormatReset(formatp* format) { - memset(format->original, 0, format->size); - format->buffer = format->original; - format->length = format->size; - return; -} - -void BeaconFormatFree(formatp* format) { - if (format == NULL) { - return; - } - if (format->original) { - free(format->original); - format->original = NULL; - } - format->buffer = NULL; - format->length = 0; - format->size = 0; - return; -} - -void BeaconFormatAppend(formatp* format, char* text, int len) { - memcpy(format->buffer, text, len); - format->buffer += len; - format->length += len; - return; -} - -void BeaconFormatPrintf(formatp* format, char* fmt, ...) { - /*Take format string, and sprintf it into here*/ - va_list args; - int length = 0; - - va_start(args, fmt); - length = vsnprintf(NULL, 0, fmt, args); - va_end(args); - if (format->length + length > format->size) { - return; - } - - va_start(args, fmt); - (void)vsnprintf(format->buffer, length, fmt, args); - va_end(args); - format->length += length; - format->buffer += length; - return; -} - - -char* BeaconFormatToString(formatp* format, int* size) { - *size = format->length; - return format->original; -} - -void BeaconFormatInt(formatp* format, int value) { - uint32_t indata = value; - uint32_t outdata = 0; - if (format->length + 4 > format->size) { - return; - } - outdata = swap_endianess(indata); - memcpy(format->buffer, &outdata, 4); - format->length += 4; - format->buffer += 4; - return; -} - -/* Main output functions */ - -void BeaconPrintf(int type, char* fmt, ...) { - /* Change to maintain internal buffer, and return after done running. */ - int length = 0; - char* tempptr = NULL; - va_list args; - va_start(args, fmt); - vprintf(fmt, args); - va_end(args); - - va_start(args, fmt); - length = vsnprintf(NULL, 0, fmt, args); - va_end(args); - tempptr = realloc(beacon_compatibility_output, beacon_compatibility_size + length + 1); - if (tempptr == NULL) { - return; - } - beacon_compatibility_output = tempptr; - memset(beacon_compatibility_output + beacon_compatibility_offset, 0, length + 1); - va_start(args, fmt); - length = vsnprintf(beacon_compatibility_output + beacon_compatibility_offset, length, fmt, args); - beacon_compatibility_size += length; - beacon_compatibility_offset += length; - va_end(args); - return; -} - -void BeaconOutput(int type, char* data, int len) { - char* tempptr = NULL; - tempptr = realloc(beacon_compatibility_output, beacon_compatibility_size + len + 1); - beacon_compatibility_output = tempptr; - if (tempptr == NULL) { - return; - } - memset(beacon_compatibility_output + beacon_compatibility_offset, 0, len + 1); - memcpy(beacon_compatibility_output + beacon_compatibility_offset, data, len); - beacon_compatibility_size += len; - beacon_compatibility_offset += len; - return; -} - -/* Token Functions */ - -BOOL BeaconUseToken(HANDLE token) { - /* Probably needs to handle DuplicateTokenEx too */ - SetThreadToken(NULL, token); - return TRUE; -} - -void BeaconRevertToken(void) { - if (!RevertToSelf()) { -#ifdef DEBUG - printf("RevertToSelf Failed!\n"); -#endif - } - return; -} - -BOOL BeaconIsAdmin(void) { - /* Leaving this to be implemented by people needing it */ -#ifdef DEBUG - printf("BeaconIsAdmin Called\n"); -#endif - return FALSE; -} - -/* Injection/spawning related stuffs - * - * These functions are basic place holders, and if implemented into something - * real should be just calling internal functions for your tools. */ -void BeaconGetSpawnTo(BOOL x86, char* buffer, int length) { - char* tempBufferPath = NULL; - if (buffer == NULL) { - return; - } - if (x86) { - tempBufferPath = "C:\\Windows\\"X86PATH"\\"DEFAULTPROCESSNAME; - if (strlen(tempBufferPath) > length) { - return; - } - memcpy(buffer, tempBufferPath, strlen(tempBufferPath)); - } - else { - tempBufferPath = "C:\\Windows\\"X64PATH"\\"DEFAULTPROCESSNAME; - if (strlen(tempBufferPath) > length) { - return; - } - memcpy(buffer, tempBufferPath, strlen(tempBufferPath)); - - } - return; -} - -BOOL BeaconSpawnTemporaryProcess(BOOL x86, BOOL ignoreToken, STARTUPINFO* sInfo, PROCESS_INFORMATION* pInfo) { - BOOL bSuccess = FALSE; - if (x86) { - bSuccess = CreateProcessA(NULL, (char*)"C:\\Windows\\"X86PATH"\\"DEFAULTPROCESSNAME, NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, sInfo, pInfo); - } - else { - bSuccess = CreateProcessA(NULL, (char*)"C:\\Windows\\"X64PATH"\\"DEFAULTPROCESSNAME, NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, sInfo, pInfo); - } - return bSuccess; -} - -void BeaconInjectProcess(HANDLE hProc, int pid, char* payload, int p_len, int p_offset, char* arg, int a_len) { - /* Leaving this to be implemented by people needing/wanting it */ - return; -} - -void BeaconInjectTemporaryProcess(PROCESS_INFORMATION* pInfo, char* payload, int p_len, int p_offset, char* arg, int a_len) { - /* Leaving this to be implemented by people needing/wanting it */ - return; -} - -void BeaconCleanupProcess(PROCESS_INFORMATION* pInfo) { - (void)CloseHandle(pInfo->hThread); - (void)CloseHandle(pInfo->hProcess); - return; -} - -BOOL toWideChar(char* src, wchar_t* dst, int max) { - /* Leaving this to be implemented by people needing/wanting it */ - return FALSE; -} - -char* BeaconGetOutputData(int* outsize) { - char* outdata = beacon_compatibility_output; - if (outsize) - *outsize = beacon_compatibility_size; - beacon_compatibility_output = NULL; - beacon_compatibility_size = 0; - beacon_compatibility_offset = 0; - return outdata; -} - -#endif diff --git a/src/zcoff/src/beacon_compatibility.h b/src/zcoff/src/beacon_compatibility.h deleted file mode 100644 index f1e716e..0000000 --- a/src/zcoff/src/beacon_compatibility.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Cobalt Strike 4.X BOF compatibility layer - * ----------------------------------------- - * The whole point of these files are to allow beacon object files built for CS - * to run fine inside of other tools without recompiling. - * - * Built off of the beacon.h file provided to build for CS. - */ - -#include - -#ifndef BEACON_COMPATIBILITY_H_ - /* Structures as is in beacon.h */ -extern unsigned char* InternalFunctions[25][2]; -typedef struct { - char* original; /* the original buffer [so we can free it] */ - char* buffer; /* current pointer into our buffer */ - int length; /* remaining length of data */ - int size; /* total size of this buffer */ -} datap; - -typedef struct { - char* original; /* the original buffer [so we can free it] */ - char* buffer; /* current pointer into our buffer */ - int length; /* remaining length of data */ - int size; /* total size of this buffer */ -} formatp; - -void BeaconDataParse(datap* parser, char* buffer, int size); -int BeaconDataInt(datap* parser); -short BeaconDataShort(datap* parser); -int BeaconDataLength(datap* parser); -char* BeaconDataExtract(datap* parser, int* size); - -void BeaconFormatAlloc(formatp* format, int maxsz); -void BeaconFormatReset(formatp* format); -void BeaconFormatFree(formatp* format); -void BeaconFormatAppend(formatp* format, char* text, int len); -void BeaconFormatPrintf(formatp* format, char* fmt, ...); -char* BeaconFormatToString(formatp* format, int* size); -void BeaconFormatInt(formatp* format, int value); - -#define CALLBACK_OUTPUT 0x0 -#define CALLBACK_OUTPUT_OEM 0x1e -#define CALLBACK_ERROR 0x0d -#define CALLBACK_OUTPUT_UTF8 0x20 - - -void BeaconPrintf(int type, char* fmt, ...); -void BeaconOutput(int type, char* data, int len); - -/* Token Functions */ -BOOL BeaconUseToken(HANDLE token); -void BeaconRevertToken(); -BOOL BeaconIsAdmin(); - -/* Spawn+Inject Functions */ -void BeaconGetSpawnTo(BOOL x86, char* buffer, int length); -BOOL BeaconSpawnTemporaryProcess(BOOL x86, BOOL ignoreToken, STARTUPINFO* sInfo, PROCESS_INFORMATION* pInfo); -void BeaconInjectProcess(HANDLE hProc, int pid, char* payload, int p_len, int p_offset, char* arg, int a_len); -void BeaconInjectTemporaryProcess(PROCESS_INFORMATION* pInfo, char* payload, int p_len, int p_offset, char* arg, int a_len); -void BeaconCleanupProcess(PROCESS_INFORMATION* pInfo); - -/* Utility Functions */ -BOOL toWideChar(char* src, wchar_t* dst, int max); -uint32_t swap_endianess(uint32_t indata); - -char* BeaconGetOutputData(int* outsize); -#endif diff --git a/src/zcoff/src/coff_definitions.h b/src/zcoff/src/coff_definitions.h deleted file mode 100644 index 610c4e2..0000000 --- a/src/zcoff/src/coff_definitions.h +++ /dev/null @@ -1,118 +0,0 @@ -#pragma once -#include - -// -//Microsoft COFF Header -//Section Headers -//Raw Data : -//code -//data -//debug info -//relocations -#pragma pack (push, 1) -typedef struct { - UINT16 Machine; - UINT16 NumberOfSections; - UINT32 TimeDateStamp; - UINT32 PointerToSymbolTable; - UINT32 NumberOfSymbols; - UINT16 SizeOfOptionalHeader; - UINT16 Characteristics; -} FileHeader; - - -/// -/// Just a test! -/// -typedef struct { - char Name[8]; //8 bytes long null-terminated string - UINT32 VirtualSize; //total size of section when loaded into memory, 0 for COFF, might be different because of padding - UINT32 VirtualAddress; //address of the first byte of the section before relocations are applied, should be set to 0 - UINT32 SizeOfRawData; //The size of the section for COFF files - UINT32 PointerToRawData; //Pointer to the beginning of the section for COFF - UINT32 PointerToRelocations; //File pointer to the beginning of relocation entries - UINT32 PointerToLinenumbers; //The file pointer to the beginning of line-number entries for the section. T - UINT16 NumberOfRelocations; //The number of relocation entries for the section. This is set to zero for executable images. - UINT16 NumberOfLinenumbers; //The number of line-number entries for the section. This value should be zero for an image because COFF debugging information is deprecated. - UINT32 Characteristics; //The flags that describe the characteristics of the section -} SectionHeader; - - -typedef struct { - union { - char Name[8]; //8 bytes, name of the symbol, represented as a union of 3 structs - UINT32 value[2]; //TODO: what does this represent?! - } first; - UINT32 Value; //meaning depends on the section number and storage class - UINT16 SectionNumber; //signed int, some values have predefined meaning - UINT16 Type; // - UINT8 StorageClass; // - UINT8 NumberOfAuxSymbols; -} SymbolTableEntry; - - -typedef struct { - UINT32 VirtualAddress; - UINT32 SymbolTableIndex; - UINT16 Type; -} RelocationTableEntry; - -#pragma pack(pop) - - -#define IMAGE_REL_AMD64_ABSOLUTE 0x0000 -#define IMAGE_REL_AMD64_ADDR64 0x0001 -#define IMAGE_REL_AMD64_ADDR32 0x0002 -#define IMAGE_REL_AMD64_ADDR32NB 0x0003 -/* Most common from the looks of it, just 32-bit relative address from the byte following the relocation */ -#define IMAGE_REL_AMD64_REL32 0x0004 -/* Second most common, 32-bit address without an image base. Not sure what that means... */ -#define IMAGE_REL_AMD64_REL32_1 0x0005 -#define IMAGE_REL_AMD64_REL32_2 0x0006 -#define IMAGE_REL_AMD64_REL32_3 0x0007 -#define IMAGE_REL_AMD64_REL32_4 0x0008 -#define IMAGE_REL_AMD64_REL32_5 0x0009 -#define IMAGE_REL_AMD64_SECTION 0x000A -#define IMAGE_REL_AMD64_SECREL 0x000B -#define IMAGE_REL_AMD64_SECREL7 0x000C -#define IMAGE_REL_AMD64_TOKEN 0x000D -#define IMAGE_REL_AMD64_SREL32 0x000E -#define IMAGE_REL_AMD64_PAIR 0x000F -#define IMAGE_REL_AMD64_SSPAN32 0x0010 - - -// -// Storage classes. -// -#define IMAGE_SYM_CLASS_END_OF_FUNCTION (BYTE )-1 -#define IMAGE_SYM_CLASS_NULL 0x0000 -#define IMAGE_SYM_CLASS_AUTOMATIC 0x0001 -#define IMAGE_SYM_CLASS_EXTERNAL 0x0002 -#define IMAGE_SYM_CLASS_STATIC 0x0003 -#define IMAGE_SYM_CLASS_REGISTER 0x0004 -#define IMAGE_SYM_CLASS_EXTERNAL_DEF 0x0005 -#define IMAGE_SYM_CLASS_LABEL 0x0006 -#define IMAGE_SYM_CLASS_UNDEFINED_LABEL 0x0007 -#define IMAGE_SYM_CLASS_MEMBER_OF_STRUCT 0x0008 -#define IMAGE_SYM_CLASS_ARGUMENT 0x0009 -#define IMAGE_SYM_CLASS_STRUCT_TAG 0x000A -#define IMAGE_SYM_CLASS_MEMBER_OF_UNION 0x000B -#define IMAGE_SYM_CLASS_UNION_TAG 0x000C -#define IMAGE_SYM_CLASS_TYPE_DEFINITION 0x000D -#define IMAGE_SYM_CLASS_UNDEFINED_STATIC 0x000E -#define IMAGE_SYM_CLASS_ENUM_TAG 0x000F -#define IMAGE_SYM_CLASS_MEMBER_OF_ENUM 0x0010 -#define IMAGE_SYM_CLASS_REGISTER_PARAM 0x0011 -#define IMAGE_SYM_CLASS_BIT_FIELD 0x0012 -#define IMAGE_SYM_CLASS_FAR_EXTERNAL 0x0044 -#define IMAGE_SYM_CLASS_BLOCK 0x0064 -#define IMAGE_SYM_CLASS_FUNCTION 0x0065 -#define IMAGE_SYM_CLASS_END_OF_STRUCT 0x0066 -#define IMAGE_SYM_CLASS_FILE 0x0067 -#define IMAGE_SYM_CLASS_SECTION 0x0068 -#define IMAGE_SYM_CLASS_WEAK_EXTERNAL 0x0069 -#define IMAGE_SYM_CLASS_CLR_TOKEN 0x006B - - -//the $ is used to group sections in object files. It doesn't exist in image files -//the linker will remove $ and its suffix. sect1$c comes before sect1$c and after sect1$a \ No newline at end of file diff --git a/src/zcoff/xmake.lua b/src/zcoff/xmake.lua deleted file mode 100644 index 275b017..0000000 --- a/src/zcoff/xmake.lua +++ /dev/null @@ -1,7 +0,0 @@ -target("zcoff") - set_rundir(".") - set_kind("binary") - add_files("src/*.c") - add_syslinks("Advapi32") - add_headerfiles("src/*.h") - set_runargs("file/main.cpp.obj") \ No newline at end of file diff --git a/src/zelf/file/main.cpp.obj b/src/zelf/file/main.cpp.obj new file mode 100644 index 0000000..bbb34b6 Binary files /dev/null and b/src/zelf/file/main.cpp.obj differ diff --git a/src/zelf/file/main.cpp.obj.id0 b/src/zelf/file/main.cpp.obj.id0 deleted file mode 100644 index 5ccb83a..0000000 Binary files a/src/zelf/file/main.cpp.obj.id0 and /dev/null differ diff --git a/src/zelf/file/zasm.exe.i64 b/src/zelf/file/zasm.exe.i64 deleted file mode 100644 index 8223162..0000000 Binary files a/src/zelf/file/zasm.exe.i64 and /dev/null differ diff --git a/src/zfile/file/SimpleSection.o b/src/zfile/file/SimpleSection.o new file mode 100644 index 0000000..8bc15eb Binary files /dev/null and b/src/zfile/file/SimpleSection.o differ diff --git a/src/zfile/file/main.cpp.obj b/src/zfile/file/main.cpp.obj new file mode 100644 index 0000000..bbb34b6 Binary files /dev/null and b/src/zfile/file/main.cpp.obj differ diff --git a/src/zfile/file/main.cpp2.obj b/src/zfile/file/main.cpp2.obj new file mode 100644 index 0000000..109c49e Binary files /dev/null and b/src/zfile/file/main.cpp2.obj differ diff --git a/src/zfile/file/zfile.exe b/src/zfile/file/zfile.exe new file mode 100644 index 0000000..55ded62 Binary files /dev/null and b/src/zfile/file/zfile.exe differ diff --git a/src/zfile/src/coff/coff.h b/src/zfile/src/coff/coff.h new file mode 100644 index 0000000..d8742c7 --- /dev/null +++ b/src/zfile/src/coff/coff.h @@ -0,0 +1,51 @@ +#pragma once +#include +/* sizeof 20 */ +typedef struct coff_file_header { + uint16_t Machine; + uint16_t NumberOfSections; + uint32_t TimeDateStamp; + uint32_t PointerToSymbolTable; + uint32_t NumberOfSymbols; + uint16_t SizeOfOptionalHeader; + uint16_t Characteristics; +} coff_file_header_t; + +/* AMD64 should always be here */ +#define MACHINETYPE_AMD64 0x8664 + +#pragma pack(push,1) + +/* Size of 40 */ +typedef struct coff_sect { + char Name[8]; + uint32_t VirtualSize; + uint32_t VirtualAddress; + uint32_t SizeOfRawData; + uint32_t PointerToRawData; + uint32_t PointerToRelocations; + uint32_t PointerToLineNumbers; + uint16_t NumberOfRelocations; + uint16_t NumberOfLinenumbers; + uint32_t Characteristics; +} coff_sect_t; + + +typedef struct coff_reloc { + uint32_t VirtualAddress; + uint32_t SymbolTableIndex; + uint16_t Type; +} coff_reloc_t; + +typedef struct coff_sym { + union { + char Name[8]; + uint32_t value[2]; + } first; + uint32_t Value; + uint16_t SectionNumber; + uint16_t Type; + uint8_t StorageClass; + uint8_t NumberOfAuxSymbols; + +} coff_sym_t; \ No newline at end of file diff --git a/src/zfile/src/coff/coff64.cpp b/src/zfile/src/coff/coff64.cpp new file mode 100644 index 0000000..c856019 --- /dev/null +++ b/src/zfile/src/coff/coff64.cpp @@ -0,0 +1,57 @@ +#include "coff64.h" + +void Coff64::Serialize(IArchive& Ar) +{ + IsSerialize = true; + Ar.Seek(0, sizeof(Header)); + Ar.Serialize(&Header); + int num = Header.NumberOfSections; + SectList = (coff_sect*)appMalloc(num * sizeof(coff_sect)); + SectDataList = (Coff64_Sect_Data*)appMalloc(num * sizeof(Coff64_Sect_Data)); + for (int i = 0; i < num; i++) { + coff_sect& sect = SectList[i]; + Ar.Seek(sizeof(Header) + i * sizeof(sect), sizeof(sect)); + Ar.Serialize(§); + Coff64_Sect_Data& sect_data = SectDataList[i]; + sect_data.Serialize(Ar, sect); + } +} + +bool Coff64::CheckFile(IArchive& Ar) +{ + Ar.Seek(0, sizeof(Header)); + Ar.Serialize(&Header); + char* e_ident = (char*)&Header.Machine; + if (e_ident[0] != '\x64' || e_ident[1] != '\x86') + return false; + return true; +} + +void Coff64::PrintTest() +{ +} + +Coff64::~Coff64() +{ + if (!IsSerialize) + return; + int num = Header.NumberOfSections; + for (int i = 0; i < num; i++) { + Coff64_Sect_Data& sect_data = SectDataList[i]; + if (sect_data.Data) + appFree(sect_data.Data); + } + appFree(SectList); + appFree(SectDataList); +} + +void Coff64_Sect_Data::Serialize(IArchive& Ar, coff_sect& sect) +{ + Size = sect.SizeOfRawData; + Data = nullptr; + if (Size) { + Data = (char*)appMalloc(Size); + Ar.Seek(sect.PointerToRawData, Size); + Ar.Serialize(&Data); + } +} diff --git a/src/zfile/src/coff/coff64.h b/src/zfile/src/coff/coff64.h new file mode 100644 index 0000000..12d0025 --- /dev/null +++ b/src/zfile/src/coff/coff64.h @@ -0,0 +1,23 @@ +#pragma once +#include "core/package.h" +#include "coff.h" +class Coff64; +class Coff64_Sect_Data { +public: + int Size; + char* Data; +public: + void Serialize(IArchive& Ar, coff_sect& sect); +}; +class Coff64 : public IPackage { +public: + coff_file_header_t Header; + coff_sect* SectList; + Coff64_Sect_Data* SectDataList; +public: + virtual void Serialize(IArchive& Ar) override; + virtual bool CheckFile(IArchive& Ar) override; + virtual void PrintTest() override; +public: + ~Coff64(); +}; \ No newline at end of file diff --git a/src/zfile/src/core/archive.cpp b/src/zfile/src/core/archive.cpp new file mode 100644 index 0000000..eeb40fa --- /dev/null +++ b/src/zfile/src/core/archive.cpp @@ -0,0 +1,51 @@ +#include "Archive.h" +#include + +FrameStack* FrameStack::Frame = nullptr; + +void* FrameStack::MakeMalloc(int size) { + Size = size; + void* data = malloc(Size); + if (!data) { + appError("malloc data error"); + return nullptr; + }else if (Data) { + memcpy(data, Data, Pos); + free(Data); + } + Data = data; + return Data; +} +void* FrameStack::AppMalloc(int size) +{ + int pos = Pos + Start; + if (Stop > 0 && pos + size > Stop) + appError("malloc behind stopper (%X+%X > %X)", pos, size, Stop); + else if (pos + size > Size) { + MakeMalloc(Size * 2); + } + Pos += size; + return (char*)Data+pos; +} +void* FrameStack::SAppMalloc(int size) +{ + if (Frame) { + return Frame->AppMalloc(size); + } + return nullptr; +} +FArchive::FArchive(char* file) +{ + FILE* fi = fopen(file, "rb"); + if (!fi) { + appError("file %s not exists", file); + return; + } + fseek(fi, 0, SEEK_END); + Size = ftell(fi); + Data = new char[Size]; + rewind(fi); + fread(Data, sizeof(char), Size, fi); + fclose(fi); +} + diff --git a/src/zfile/src/core/archive.h b/src/zfile/src/core/archive.h new file mode 100644 index 0000000..d735870 --- /dev/null +++ b/src/zfile/src/core/archive.h @@ -0,0 +1,68 @@ +#pragma once +#include +#include +#include +#define appError +#define appLog +#define appMalloc FrameStack::SAppMalloc +#define appFree FrameStack::SFree +class FrameStack { +public: + void* Data = nullptr; + int Pos = 0; + int Start = 0; + int Stop = 0; + int Size = 0; + static FrameStack* Frame; +public: + void* MakeMalloc(int size); + void* AppMalloc(int size); + static void* SAppMalloc(int size); + static void SFree(void* ptr) {}; +}; + +class IArchive +{ +public: + virtual void Seek(int start = -1, int offset = -1) = 0; + virtual void Serialize(void* data, int size) = 0; + virtual void Serialize(void* data) = 0; +private: + +}; +class FArchive : public IArchive { +protected: + int Pos = 0; + int Start = 0; + int Stop = 0; + int Size = 0; + char* Data = nullptr; +public: + FArchive(char* file); + virtual void Seek(int start = -1, int offset = -1) override + { + start = start < 0 ? Pos : start; + int stop = offset < 0 ? -1 : start + offset; + assert(start <= Size && stop <= Size); + Pos = 0; + Start = start; + Stop = stop; + } + virtual void Serialize(void* data, int size) override + { + int pos = Pos + Start; + if (size == 0) { + size = Stop < 0 ? Size - pos : Stop - pos; + } + if (Stop > 0 && pos + size > Stop) + appError("Serializing behind stopper (%X+%X > %X)", pos, size, Stop); + else if (pos + size > Size) + appError("Serializing behind end of buffer"); + memcpy(data, Data + pos, size); + Pos += size; + } + virtual void Serialize(void* data) override + { + Serialize(data, 0); + } +}; \ No newline at end of file diff --git a/src/zfile/src/core/package.cpp b/src/zfile/src/core/package.cpp new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/zfile/src/core/package.cpp @@ -0,0 +1 @@ + diff --git a/src/zfile/src/core/package.h b/src/zfile/src/core/package.h new file mode 100644 index 0000000..c0d5f2b --- /dev/null +++ b/src/zfile/src/core/package.h @@ -0,0 +1,12 @@ +#pragma once +#include "Archive.h" +class IPackage { +protected: + bool IsSerialize = false; +public: + virtual void Serialize(IArchive& Ar) = 0; + virtual bool CheckFile(IArchive& Ar) = 0; + virtual void PrintTest() = 0; +private: + +}; \ No newline at end of file diff --git a/src/zfile/src/elf/elf.h b/src/zfile/src/elf/elf.h new file mode 100644 index 0000000..1441668 --- /dev/null +++ b/src/zfile/src/elf/elf.h @@ -0,0 +1,60 @@ +#pragma once +#include +/* + * ELF standard typedefs (yet more proof that was way overdue) + */ + +typedef uint16_t Elf32_Half; +typedef int16_t Elf32_SHalf; +typedef uint32_t Elf32_Word; +typedef int32_t Elf32_Sword; +typedef uint64_t Elf32_Xword; +typedef int64_t Elf32_Sxword; + +typedef uint32_t Elf32_Off; +typedef uint32_t Elf32_Addr; +typedef uint16_t Elf32_Section; + +typedef uint16_t Elf64_Half; +typedef int16_t Elf64_SHalf; +typedef uint32_t Elf64_Word; +typedef int32_t Elf64_Sword; +typedef uint64_t Elf64_Xword; +typedef int64_t Elf64_Sxword; + +typedef uint64_t Elf64_Off; +typedef uint64_t Elf64_Addr; +typedef uint16_t Elf64_Section; + +/* Length of magic at the start of a file */ +#define EI_NIDENT 16 + +typedef struct elf64_hdr { + unsigned char e_ident[EI_NIDENT]; + Elf64_Half e_type; + Elf64_Half e_machine; + Elf64_Word e_version; + Elf64_Addr e_entry; + Elf64_Off e_phoff; + Elf64_Off e_shoff; + Elf64_Word e_flags; + Elf64_Half e_ehsize; + Elf64_Half e_phentsize; + Elf64_Half e_phnum; + Elf64_Half e_shentsize; + Elf64_Half e_shnum; + Elf64_Half e_shstrndx; +} Elf64_Ehdr; + +typedef struct elf64_shdr { + Elf64_Word sh_name; + Elf64_Word sh_type; + Elf64_Xword sh_flags; + Elf64_Addr sh_addr; + Elf64_Off sh_offset; + Elf64_Xword sh_size; + Elf64_Word sh_link; + Elf64_Word sh_info; + Elf64_Xword sh_addralign; + Elf64_Xword sh_entsize; +} Elf64_Shdr; \ No newline at end of file diff --git a/src/zfile/src/elf/elf64.cpp b/src/zfile/src/elf/elf64.cpp new file mode 100644 index 0000000..753aad5 --- /dev/null +++ b/src/zfile/src/elf/elf64.cpp @@ -0,0 +1,105 @@ +#include "elf64.h" +#include + +void Elf64::Serialize(IArchive& Ar) +{ + IsSerialize = true; + Ar.Seek(0, sizeof(Ehdr)); + Ar.Serialize(&Ehdr); + int e_shnum = Ehdr.e_shnum; + ShdrList = (Elf64_Shdr*)appMalloc(e_shnum * sizeof(Elf64_Shdr)); + ShdrDataList = (ELF64_Shdr_Data*)appMalloc(e_shnum * sizeof(ELF64_Shdr_Data)); + if (!ShdrList || !ShdrDataList) { + appError("malloc failed for elf"); + return; + } + for (int i = 0; i < e_shnum; i++) { + Elf64_Shdr& shdr = ShdrList[i]; + Ar.Seek(Ehdr.e_shoff + i * sizeof(shdr), sizeof(shdr)); + Ar.Serialize(&shdr); + ELF64_Shdr_Data& shdr_data = ShdrDataList[i]; + shdr_data.Serialize(Ar, shdr); + } +} + +bool Elf64::CheckFile(IArchive& Ar) +{ + Ar.Seek(0, sizeof(Ehdr)); + Ar.Serialize(&Ehdr); + unsigned char* e_ident = Ehdr.e_ident; + if(e_ident[1] != 'E' || e_ident[2] != 'L' || e_ident[3] != 'F') + return false; + return true; +} + +void Elf64::PrintTest() +{ + int e_shnum = Ehdr.e_shnum; + for (int i = 0; i < e_shnum; i++) { + Elf64_Shdr& shdr = ShdrList[i]; + ELF64_Shdr_Data& shdr_data = ShdrDataList[i]; + std::cout << i << shdr.sh_name << GetShStrById(shdr.sh_name) << std::endl; + } +} + +Elf64::~Elf64() +{ + if (!IsSerialize) + return; + int e_shnum = Ehdr.e_shnum; + for (int i = 0; i < e_shnum; i++) { + ELF64_Shdr_Data& shdr_data = ShdrDataList[i]; + if (shdr_data.Data) + appFree(shdr_data.Data); + } + appFree(ShdrList); + appFree(ShdrDataList); +} + +char* Elf64::GetShStrByPos(int pos) +{ + int e_shstrndx = Ehdr.e_shstrndx; + return ShdrDataList[e_shstrndx].GetStrByPos(pos); +} + +char* Elf64::GetShStrById(int id) +{ + int e_shstrndx = Ehdr.e_shstrndx; + return ShdrDataList[e_shstrndx].GetStrById(id); +} + +char* Elf64::GetStrByPos(int pos) +{ + return nullptr; +} + +char* Elf64::GetStrById(int pos) +{ + return nullptr; +} +void ELF64_Shdr_Data::Serialize(IArchive& Ar, Elf64_Shdr& shdr) +{ + Size = shdr.sh_size; + Data = nullptr; + if (Size) { + Data = (char*)appMalloc(Size); + Ar.Seek(shdr.sh_offset, Size); + Ar.Serialize(&Data); + } +} + +char* ELF64_Shdr_Data::GetStrByPos(int pos) +{ + pos = pos < Size ? pos : 0; + return &Data[pos]; +} +char* ELF64_Shdr_Data::GetStrById(int id) +{ + int i = 0 , j = 0; + while (i < Size && j < id) { + if (!Data[i++]) + j++; + } + i = i < Size ? i : 0; + return &Data[i]; +} \ No newline at end of file diff --git a/src/zfile/src/elf/elf64.h b/src/zfile/src/elf/elf64.h new file mode 100644 index 0000000..8dd6bdf --- /dev/null +++ b/src/zfile/src/elf/elf64.h @@ -0,0 +1,31 @@ +#pragma once +#include "core/package.h" +#include "elf.h" +class Elf64; +class ELF64_Shdr_Data { +public: + int Size; + char* Data; +public: + void Serialize(IArchive& Ar, Elf64_Shdr& shdr); + char* GetStrByPos(int pos); + char* GetStrById(int id); +}; +class Elf64 : public IPackage { +public: + Elf64_Ehdr Ehdr; + Elf64_Shdr* ShdrList = nullptr; + ELF64_Shdr_Data* ShdrDataList = nullptr; +public: + virtual void Serialize(IArchive& Ar) override; + virtual bool CheckFile(IArchive& Ar) override; + virtual void PrintTest() override; +public: + ~Elf64(); +public: + char* GetShStrByPos(int pos); + char* GetShStrById(int pos); + + char* GetStrByPos(int pos); + char* GetStrById(int pos); +}; \ No newline at end of file diff --git a/src/zfile/src/main.cpp b/src/zfile/src/main.cpp index 7c435d2..9b37991 100644 --- a/src/zfile/src/main.cpp +++ b/src/zfile/src/main.cpp @@ -1,9 +1,28 @@ #include - +#include "elf/elf64.h" +#include "coff/coff64.h" using namespace std; - int main(int argc, char** argv) { + FrameStack frame; + FrameStack::Frame = &frame; + void* data = frame.MakeMalloc(10240); + if (!data) { + cout << "error world!" << endl; + return -1; + } + Elf64 Elf; + FArchive Ar("file/SimpleSection.o"); + if (Elf.CheckFile(Ar)) { + Elf.Serialize(Ar); + Elf.PrintTest(); + } + Coff64 Coff; + if (Coff.CheckFile(Ar)) { + Coff.Serialize(Ar); + Coff.PrintTest(); + } + free(data); cout << "hello world!" << endl; return 0; } diff --git a/src/zfile/src/parse.cpp b/src/zfile/src/parse.cpp deleted file mode 100644 index e739fa3..0000000 --- a/src/zfile/src/parse.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include "parse.h" -#include - -void FilePackage::Serialize(FArchive& Ar) -{ - FileHeader st; - Ar.Serialize(&st, sizeof(FileHeader)); - -} diff --git a/src/zfile/src/parse.h b/src/zfile/src/parse.h deleted file mode 100644 index 803d340..0000000 --- a/src/zfile/src/parse.h +++ /dev/null @@ -1,66 +0,0 @@ -#include - -#define UINT16 unsigned int -#define UINT32 unsigned int -#define BYTES unsigned char* -#define byte unsigned char -#define appError -class FArchive { -protected: - int ArPos; - int ArStarter; - int ArStopper; - int DataSize; - const byte* DataPtr; -private: - -public: - virtual void Seek(int Pos) - { - Pos += ArStarter; - assert(Pos >= 0 && Pos <= DataSize); - ArPos = Pos; - } - virtual void Serialize(void* data, int size) - { - if (ArStopper > 0 && ArPos + size > ArStopper) - appError("Serializing behind stopper (%X+%X > %X)", ArPos, size, ArStopper); - else if (ArPos + size > DataSize) - appError("Serializing behind end of buffer"); - memcpy(data, DataPtr + ArPos, size); - ArPos += size; - } -public: - virtual bool IsEof() const - { - return ArPos >= DataSize; - } -}; -typedef struct { - UINT16 Machine; - UINT16 NumberOfSections; - UINT32 TimeDateStamp; - UINT32 PointerToSymbolTable; - UINT32 NumberOfSymbols; - UINT16 SizeOfOptionalHeader; - UINT16 Characteristics; -} FileHeader; -typedef struct { - char Name[8]; //8 bytes long null-terminated string - UINT32 VirtualSize; //total size of section when loaded into memory, 0 for COFF, might be different because of padding - UINT32 VirtualAddress; //address of the first byte of the section before relocations are applied, should be set to 0 - UINT32 SizeOfRawData; //The size of the section for COFF files - UINT32 PointerToRawData; //Pointer to the beginning of the section for COFF - UINT32 PointerToRelocations; //File pointer to the beginning of relocation entries - UINT32 PointerToLinenumbers; //The file pointer to the beginning of line-number entries for the section. T - UINT16 NumberOfRelocations; //The number of relocation entries for the section. This is set to zero for executable images. - UINT16 NumberOfLinenumbers; //The number of line-number entries for the section. This value should be zero for an image because COFF debugging information is deprecated. - UINT32 Characteristics; //The flags that describe the characteristics of the section -} SectionHeader; -class FilePackage { - -public: - virtual void Serialize(FArchive& Ar); -private: - -}; \ No newline at end of file diff --git a/src/zfile/xmake.lua b/src/zfile/xmake.lua index 0c7c665..db67dd0 100644 --- a/src/zfile/xmake.lua +++ b/src/zfile/xmake.lua @@ -2,8 +2,10 @@ add_rules("mode.debug", "mode.release") target("zfile") set_kind("binary") - add_files("src/*.cpp") - add_headerfiles("src/*.h") + set_rundir(".") + add_includedirs("src") + add_files("src/*.cpp","src/**/*.cpp") + add_headerfiles("src/*.h","src/**/*.h") -- -- If you want to known more usage about xmake, please see https://xmake.io diff --git a/src/zelf/file/main.cpp.obj.id1 b/src/zplus/src/ZData/ZArray.cpp similarity index 100% rename from src/zelf/file/main.cpp.obj.id1 rename to src/zplus/src/ZData/ZArray.cpp diff --git a/src/zelf/file/main.cpp.obj.nam b/src/zplus/src/ZData/ZArray.h similarity index 100% rename from src/zelf/file/main.cpp.obj.nam rename to src/zplus/src/ZData/ZArray.h