Created
February 9, 2024 01:41
-
-
Save smx-smx/8581f6d787c76f18a44b2bcffd131362 to your computer and use it in GitHub Desktop.
!linker_proxy
This file contains 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
project(linker_test) | |
macro(handle_asm_file file) | |
set_property(SOURCE "${file}" PROPERTY LANGUAGE C) | |
set_property(SOURCE "${file}" PROPERTY COMPILE_DEFINITIONS __ASSEMBLY__) | |
endmacro() | |
find_library(LIBCRYPTO_LIBRARY NAMES crypto REQUIRED) | |
message(STATUS ${LIBCRYPTO_LIBRARY}) | |
set(asm_out ${CMAKE_BINARY_DIR}/libcrypto.S) | |
set(lds_out ${CMAKE_BINARY_DIR}/libcrypto.lds) | |
add_custom_command( | |
OUTPUT ${asm_out} ${lds_out} | |
COMMAND php ${CMAKE_SOURCE_DIR}/makedef.php | |
/lib/x86_64-linux-gnu/libcrypto.so.3 ${asm_out} ${lds_out} | |
DEPENDS ${CMAKE_SOURCE_DIR}/makedef.php | |
) | |
add_custom_target(make_proxy DEPENDS libcrypto.S) | |
handle_asm_file(libcrypto.S) | |
add_executable(test | |
${asm_out} lib.c | |
) | |
target_link_options(test PRIVATE | |
-T ${lds_out} | |
"LINKER:--gc-sections" | |
#"LINKER:--print-gc-sections" | |
"LINKER:-z,start-stop-gc" | |
"LINKER:--as-needed" | |
) | |
target_link_libraries(test ${LIBCRYPTO_LIBRARY}) |
This file contains 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
/** | |
* @file lib.c | |
* @author Stefano Moioli <[email protected]> | |
* @brief | |
* @version 0.1 | |
* @date 2024-02-09 | |
* | |
* @copyright Copyright (c) 2024 | |
* | |
*/ | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <dlfcn.h> | |
extern void *X509_new(); | |
extern void *X509_STORE_CTX_new(); | |
void null_catch(){ | |
puts("STUB"); | |
} | |
extern char __start_thunks_code; | |
extern char __stop_thunks_code; | |
/** refers to the used thunk names */ | |
extern char __start_thunks_data; | |
extern char __stop_thunks_data; | |
/** refers to the used thunk pointers */ | |
extern void* __start_thunks_ptr; | |
extern void* __stop_thunks_ptr; | |
static void *lib = NULL; | |
extern char str_lib_name[]; | |
static void load_library(){ | |
lib = dlopen(str_lib_name, RTLD_GLOBAL | RTLD_LAZY); | |
if(lib == NULL){ | |
char *error = dlerror(); | |
fprintf(stderr, "dlopen() failed: %s\n", | |
error != NULL ? error : "(unknown error)"); | |
fflush(stderr); | |
abort(); | |
} | |
} | |
void *get_fptr( | |
const char *lib_name, | |
const char *func_name, | |
void **thunk_ptr | |
){ | |
printf("resolve \"%s\" \"%s\"\n", | |
lib_name, func_name); | |
void *sym = dlsym(lib, func_name); | |
if(sym == NULL){ | |
fprintf(stderr, "dlsym('%s') failed\n", func_name); | |
fflush(stderr); | |
abort(); | |
} | |
//void *fptr = &null_catch; | |
void *fptr = sym; | |
/** store the resolved symbol to avoid calling the resolved again */ | |
*thunk_ptr = fptr; | |
return fptr; | |
} | |
static void resolve_symbols(){ | |
void **ptr_start = &__start_thunks_ptr; | |
void **ptr_end = &__stop_thunks_ptr; | |
char *str_start = &__start_thunks_data; | |
char *str_end = &__stop_thunks_data; | |
for(; | |
str_start < str_end; | |
ptr_start++ | |
){ | |
char *symbol_name = str_start; | |
str_start += strlen(str_start) + 1; | |
void *sym = dlsym(lib, symbol_name); | |
if(sym == NULL){ | |
fprintf(stderr, "dlsym('%s') failed\n", symbol_name); | |
fflush(stderr); | |
abort(); | |
} | |
/** replace the fptr to point to the resolved symbol */ | |
*ptr_start = sym; | |
} | |
} | |
#define LAZY_SYMBOLS | |
void __attribute__((constructor(101))) | |
init(){ | |
printf("load %s\n", str_lib_name); | |
#ifndef LAZY_SYMBOLS | |
load_library(); | |
resolve_symbols(); | |
#endif | |
} | |
#define DEBUG | |
int main(int argc, char *argv[]){ | |
#ifdef DEBUG | |
setvbuf(stdout, NULL, _IONBF, 0); | |
setvbuf(stderr, NULL, _IONBF, 0); | |
#endif | |
puts("main"); | |
X509_new(); | |
X509_STORE_CTX_new(); | |
X509_new(); | |
X509_STORE_CTX_new(); | |
return 0; | |
} |
This file contains 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
<?php | |
/** | |
* @author Stefano Moioli <[email protected]> | |
*/ | |
function getsyms(string $lib_path){ | |
$hProc = proc_open(['nm', '-D', $lib_path], [ | |
1 => ['pipe', 'w'] | |
], $p); | |
while(!feof($p[1])){ | |
$l = rtrim(fgets($p[1])); | |
if($l === false || empty($l)) continue; | |
list($addr, $type, $name) = preg_split('/\s+/', $l, 3); | |
if($type === 'U' | |
|| str_contains($name, '@GLIBC_') | |
) { | |
continue; | |
} | |
switch($name){ | |
case '__gmon_start__': | |
case '_ITM_deregisterTMCloneTable': | |
case '_ITM_registerTMCloneTable': | |
continue 2; | |
} | |
$orig_name = $name; | |
$pos = strpos($name, '@@'); | |
if($pos !== false){ | |
$name = substr($name, 0, $pos); | |
} | |
yield [$orig_name, $name]; | |
} | |
proc_close($hProc); | |
} | |
function genproxy(string $lib_path, $asm, $lds){ | |
$lib_name = pathinfo($lib_path, PATHINFO_FILENAME); | |
fwrite($asm, <<<EOS | |
.intel_syntax noprefix | |
.section .note.GNU-stack,"",@progbits | |
//.section .thunks,"ax" | |
EOS); | |
fwrite($lds, <<<EOS | |
SECTIONS { | |
.thunks_code : | |
{ | |
__start_thunks_code = .; | |
*(SORT_BY_NAME(.thunk_code_*)) | |
__stop_thunks_code = .; | |
} | |
} | |
INSERT AFTER .text; | |
SECTIONS { | |
.thunks_data : { | |
. = ALIGN(0); | |
__start_thunks_data = .; | |
*(SORT_BY_NAME(.thunk_data_*)) | |
__stop_thunks_data = .; | |
} | |
.thunks_ptr : { | |
__start_thunks_ptr = .; | |
*(SORT_BY_NAME(.thunk_ptr*)) | |
__stop_thunks_ptr = .; | |
} | |
} | |
INSERT AFTER .data; | |
EOS); | |
$fn_ids = []; | |
$proxy_id = 0; | |
foreach(getsyms($lib_path) as $itm){ | |
list($orig_name, $name) = $itm; | |
$proxy_fn = "proxy_{$proxy_id}"; | |
$fn_ids[$proxy_id] = $name; | |
$fcall_fn = "fcall_{$proxy_id}"; | |
fwrite($asm, <<<EOS | |
.section .thunk_code_{$proxy_id},"ax" | |
//.globl {$proxy_fn} | |
.hidden {$proxy_fn} | |
{$proxy_fn}: | |
// load function name | |
lea rdi, [rip + str_lib_name] | |
lea rsi, [rip + str_{$proxy_id}] | |
lea rdx, [rip + ptr_{$proxy_id}] | |
call get_fptr | |
pushq rax | |
retq | |
.globl {$fcall_fn} | |
.hidden {$fcall_fn} | |
{$fcall_fn}: | |
pushq [rip + ptr_{$proxy_id}] | |
retq | |
EOS); | |
fwrite($lds, <<<EOS | |
"{$orig_name}" = "fcall_{$proxy_id}"; | |
EOS); | |
/*fwrite($lds, <<<EOS | |
"{$orig_name}" = "{$proxy_fn}"; | |
EOS);*/ | |
if($name != $orig_name){ | |
fwrite($lds, <<<EOS | |
"{$name}" = "{$orig_name}"; | |
EOS); | |
} | |
++$proxy_id; | |
} | |
fwrite($asm, <<<EOS | |
//.section .thunk_strings,"aS",@progbits | |
.globl str_lib_name | |
str_lib_name: .asciz "{$lib_name}" | |
EOS); | |
foreach($fn_ids as $i => $name){ | |
fwrite($asm, <<<EOS | |
.section .thunk_data_{$i},"aS",@progbits | |
str_{$i}: .asciz "{$name}" | |
.section .thunk_ptr_{$i},"aw",@progbits | |
ptr_{$i}: .quad .thunk_code_{$i} | |
EOS); | |
} | |
} | |
$lib_name = $argv[1]; | |
$out_asm = fopen($argv[2], 'w'); | |
$out_lds = fopen($argv[3], 'w'); | |
genproxy($lib_name, $out_asm, $out_lds); | |
fclose($out_asm); | |
fclose($out_lds); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment