Hello BF, I am slyat, today I will bring you guys a tutorial about basic LINUX INLINE HOOK technique.
I mean this is a kind of old school tech, but it's still quite popular. If you are interested in this, please leave a
friendly reply to unlock the following content.
WELL I GAVE UP HIDING MY CONTENT....THIS BBS SYSTEMS SEEMS HAVE SOME PROBLEM HIDING LONG CONENT,
But please leave a reply if you think this is good~~
------------------------------------------------------------------------------------------------------------------------------------------------------------------
## WHAT IS INLINE HOOK
Basically, inline hook is implemented by modifying the asam code of programs. Here is an exmaple:
push ebp
mov ebp, esp
sub esp, 0x20
Let's assume that this is the begining of a function. After inline hook, it may become like this:
jmp 0x7fffff898688
.....
When programs enter this function, it will jump to 0x7fffff898688. We change this address to our hook function.
## HOW TO HOOK?
Here are some things we should do:
1. Find the address of the target function
2. Save the first few instructions of the objective function
3. Building a springboard function
4. Change the first few instructions of the target function to the hook function
This our case, our target functions are in libc, so we should find the base address of libc first. Maybe you can just use these
code.
intptr_t get_libc_base(pid_t pid) {
intptr_t libcAddr;
char* buf;
char* end;
FILE* fd = fopen("/proc/self/maps", "r");
if(!fd)
{
printf("open maps error!");
exit(1);
}
buf = (char*) malloc(0x100);
do {
fgets(buf, 0x100, fd);
} while(!strstr(buf, "libc-"));
end = strchr(buf, '-');
libcAddr = strtol(buf, &end, 16);
// printf("The process %d's libcbase is: 0x%lx\n", pid, libcAddr);
fclose(fd);
return libcAddr;
}
pass the pid as a parameter into the function.
Once you get the base address of libc, you can find the address of target functions by adding an offset value.
intptr_t get_target_addr(intptr_t libc_base, const char* func_name) {
intptr_t funcAddr;
funcAddr = (size_t)dlsym(0, func_name);
funcAddr -= get_libc_base(getpid());
funcAddr += libc_base;
// printf("function %s address is: 0x%lx\n", func_name, funcAddr);
return funcAddr;
}
Next we are going to save the first few instructions of the objective function.
WHY? THINK OF THAT, WE STILL HAVE TO CALL THE ORIGINAL FUNCTION.
This this case, our inline hook will use push&ret jumping, its hard coding is as follow:
push Low_address ;0x68,0,0,0,0
mov dword ptr ss:[rsp+4], high_address ;0xC7,0x44,0x24,0x04,0,0,0,0
ret ;0xC3
The hard coded length is 14 bytes, so we need to save the minimum number of instructions whose object function is 14 bytes or more(WELL YOU GUY MAY THINK ABOUT THIS. lol)
*We are going to use capstone engine in order to make sure how many bytes should we save.*
I don't think installing capstone is a hard work, just follow the README file.
int get_asm_len(intptr_t target) {
csh handle;
cs_insn* insn;
size_t count;
char code[30] = {0};
int rv;
memcpy((void*)code, (void*)target, 30);
if(cs_open(CS_ARCH_X86, CS_MODE_64, &handle))
{
printf("Error: cs_open\n");
return -1;
}
count = cs_disasm(handle, code, 30, 0, 0, &insn);
if(count)
{
for(size_t i = 0; i < count; i++)
{
if (insn.address >= 14)
{
rv = insn.address;
break;
}
}
cs_free(insn, count);
}
else
{
printf("Error: cs_disasm\n");
return -1;
}
cs_close(&handle);
return rv;
}
This function will tell you how many bytes you should save, then use mencpy() to copy.(I will show the code later.)
We first obtain the address of the target function, and then use the mprotect function to change the permission of the page where the target function is located to be readabl
e, writeable, and executable.
Then we obtain the number of bytes to be saved, and allocate a space to store the saved instructions.
After the saved instructions, we put a push&set jump to return to the next instruction of the instructions saved by the target function, which is the springboard function, Ex
ecuting the springboard function is equivalent to executing the original function.
Finally, assign this address to the springboard function.
Here is the final code:
#include <stdio.h>
#include <stdlib.h>
#include <capstone/capstone.h>
#include <unistd.h>
#include <sys/types.h>
#include <dlfcn.h>
#include <sys/mman.h>
#include <string.h>
#include <stdint.h>
intptr_t get_libc_base(pid_t pid) {
intptr_t libcAddr;
char* buf;
char* end;
FILE* fd = fopen("/proc/self/maps", "r");
if(!fd) {
printf("open maps error!");
exit(1);
}
buf = (char*) malloc(0x100);
do {
fgets(buf, 0x100, fd);
} while(!strstr(buf, "libc-"));
end = strchr(buf, '-');
libcAddr = strtol(buf, &end, 16);
// printf("The process %d's libcbase is: 0x%lx\n", pid, libcAddr);
fclose(fd);
return libcAddr;
}
intptr_t get_target_addr(intptr_t libc_base, const char* func_name) {
intptr_t funcAddr;
funcAddr = (size_t)dlsym(0, func_name);
funcAddr -= get_libc_base(getpid());
funcAddr += libc_base;
// printf("function %s address is: 0x%lx\n", func_name, funcAddr);
return funcAddr;
}
int get_asm_len(intptr_t target) {
csh handle;
cs_insn* insn;
size_t count;
char code[30] = {0};
int rv;
memcpy((void*)code, (void*)target, 30);
if(cs_open(CS_ARCH_X86, CS_MODE_64, &handle))
{
printf("Error: cs_open\n");
return -1;
}
count = cs_disasm(handle, code, 30, 0, 0, &insn);
if(count)
{
for(size_t i = 0; i < count; i++)
{
if (insn.address >= 14)
{
rv = insn.address;
break;
}
}
cs_free(insn, count);
}
else
{
printf("Error: cs_disasm\n");
return -1;
}
cs_close(&handle);
return rv;
}
// replace few bytes
void change_bytes(intptr_t addr, const char code[], int len)
{
memcpy((void*)addr, code, len);
}
void func_hook(const char* funcname, void* hook_func, void** origin_func)
{
intptr_t libc_base = get_libc_base(getpid());
intptr_t target_addr = get_target_addr(libc_base, funcname);
intptr_t page_start = target_addr & 0xfffffffff000;
mprotect((void*)page_start, 0x1000, PROT_READ|PROT_WRITE|PROT_EXEC);
int asm_len = get_asm_len(target_addr);
if(asm_len <= 0)
{
printf("Error: get_asm_len\n");
exit(-1);
}
char* temp_func = (char*)mmap(NULL, 4096, PROT_WRITE|PROT_EXEC|PROT_READ, MAP_ANON|MAP_PRIVATE, -1, 0);
memcpy((void*)temp_func, (void*)target_addr, asm_len);
intptr_t y = (intptr_t)target_addr + asm_len;
//build push&ret jump
char jmp_code[14] = {0x68,y&0xff,(y&0xff00)>>8,(y&0xff0000)>>16,(y&0xff000000)>>24,
0xC7,0x44,0x24,0x04,(y&0xff00000000)>>32,(y&0xff0000000000)>>40,(y&0xff000000000000)>>48,
(y&0xff00000000000000)>>56,0xC3};
memcpy((void*)(temp_func+asm_len), (void*)jmp_code, 14);
*origin_func = (void*)temp_func;
intptr_t x = (intptr_t)hook_func;
char hard_code[14] = {0x68,x&0xff,(x&0xff00)>>8,(x&0xff0000)>>16,(x&0xff000000)>>24,
0xC7,0x44,0x24,0x04,(x&0xff00000000)>>32,(x&0xff0000000000)>>40,(x&0xff000000000000)>>48,
(x&0xff00000000000000)>>56,0xC3};
change_bytes(target_addr, hard_code, 14);
}
static FILE* (*origin_fopen)(const char* filename, const char* mod);
static int (*origin_fclose)(FILE* fp);
static FILE* fopen_hook(const char* filename, const char* mod)
{
FILE* rv = origin_fopen(filename, mod);
printf("fopen(\"%s\", \"%s\")\n\treturn: %p\n", filename, mod, rv);
return rv;
}
static int fclose_hook(FILE* fp) {
int rv = origin_fclose(fp);
printf("fclose(%p)\n\treturn: %d\n", fp, rv);
return rv;
}
int main() {
func_hook("fopen", (void*)fopen_hook, (void**)&origin_fopen);
func_hook("fclose", (void*)fclose_hook, (void**)&origin_fclose);
FILE* file = fopen("breached.io", "r");
if (file != NULL)
{
fclose(file);
}
return 0;
}
Well, I know it's quite long, but I've explained most of them.....
## GOBAL HOOK
For now we can just hook the functions in our process, seems useless. We need to compile it to a so file and inject it to other programs.
Add these few line of code and delete main():
__attribute__((constructor))
void load()
{
func_hook("fopen", (void*)fopen_hook, (void**)&origin_fopen);
func_hook("fclose", (void*)fclose_hook, (void**)&origin_fclose);
printf("inject suceessfully\n");
}
These code will be execute whenever the so is loaded.
use this command to compile it:
gcc -shared -fPIC libhook.c -o libhook.so -ldl -lcapstone
FIND A SO INJECTOR ON GITHUB AND INJECT OUR SO.(Easy part, if you have difficulty doing this, well, you should get a better understanding of linux system~ not offensive)
All in all, thank you guys for watching this tutorial. If you think this is a good shit, leave a reply and a like. Or if you think this thing sucks, PLEASE TELL ME AND I WILL IMPROVE!!!!!
I mean this is a kind of old school tech, but it's still quite popular. If you are interested in this, please leave a
friendly reply to unlock the following content.
WELL I GAVE UP HIDING MY CONTENT....THIS BBS SYSTEMS SEEMS HAVE SOME PROBLEM HIDING LONG CONENT,
But please leave a reply if you think this is good~~
------------------------------------------------------------------------------------------------------------------------------------------------------------------
## WHAT IS INLINE HOOK
Basically, inline hook is implemented by modifying the asam code of programs. Here is an exmaple:
push ebp
mov ebp, esp
sub esp, 0x20
Let's assume that this is the begining of a function. After inline hook, it may become like this:
jmp 0x7fffff898688
.....
When programs enter this function, it will jump to 0x7fffff898688. We change this address to our hook function.
## HOW TO HOOK?
Here are some things we should do:
1. Find the address of the target function
2. Save the first few instructions of the objective function
3. Building a springboard function
4. Change the first few instructions of the target function to the hook function
This our case, our target functions are in libc, so we should find the base address of libc first. Maybe you can just use these
code.
intptr_t get_libc_base(pid_t pid) {
intptr_t libcAddr;
char* buf;
char* end;
FILE* fd = fopen("/proc/self/maps", "r");
if(!fd)
{
printf("open maps error!");
exit(1);
}
buf = (char*) malloc(0x100);
do {
fgets(buf, 0x100, fd);
} while(!strstr(buf, "libc-"));
end = strchr(buf, '-');
libcAddr = strtol(buf, &end, 16);
// printf("The process %d's libcbase is: 0x%lx\n", pid, libcAddr);
fclose(fd);
return libcAddr;
}
pass the pid as a parameter into the function.
Once you get the base address of libc, you can find the address of target functions by adding an offset value.
intptr_t get_target_addr(intptr_t libc_base, const char* func_name) {
intptr_t funcAddr;
funcAddr = (size_t)dlsym(0, func_name);
funcAddr -= get_libc_base(getpid());
funcAddr += libc_base;
// printf("function %s address is: 0x%lx\n", func_name, funcAddr);
return funcAddr;
}
Next we are going to save the first few instructions of the objective function.
WHY? THINK OF THAT, WE STILL HAVE TO CALL THE ORIGINAL FUNCTION.
This this case, our inline hook will use push&ret jumping, its hard coding is as follow:
push Low_address ;0x68,0,0,0,0
mov dword ptr ss:[rsp+4], high_address ;0xC7,0x44,0x24,0x04,0,0,0,0
ret ;0xC3
The hard coded length is 14 bytes, so we need to save the minimum number of instructions whose object function is 14 bytes or more(WELL YOU GUY MAY THINK ABOUT THIS. lol)
*We are going to use capstone engine in order to make sure how many bytes should we save.*
I don't think installing capstone is a hard work, just follow the README file.
int get_asm_len(intptr_t target) {
csh handle;
cs_insn* insn;
size_t count;
char code[30] = {0};
int rv;
memcpy((void*)code, (void*)target, 30);
if(cs_open(CS_ARCH_X86, CS_MODE_64, &handle))
{
printf("Error: cs_open\n");
return -1;
}
count = cs_disasm(handle, code, 30, 0, 0, &insn);
if(count)
{
for(size_t i = 0; i < count; i++)
{
if (insn.address >= 14)
{
rv = insn.address;
break;
}
}
cs_free(insn, count);
}
else
{
printf("Error: cs_disasm\n");
return -1;
}
cs_close(&handle);
return rv;
}
This function will tell you how many bytes you should save, then use mencpy() to copy.(I will show the code later.)
We first obtain the address of the target function, and then use the mprotect function to change the permission of the page where the target function is located to be readabl
e, writeable, and executable.
Then we obtain the number of bytes to be saved, and allocate a space to store the saved instructions.
After the saved instructions, we put a push&set jump to return to the next instruction of the instructions saved by the target function, which is the springboard function, Ex
ecuting the springboard function is equivalent to executing the original function.
Finally, assign this address to the springboard function.
Here is the final code:
#include <stdio.h>
#include <stdlib.h>
#include <capstone/capstone.h>
#include <unistd.h>
#include <sys/types.h>
#include <dlfcn.h>
#include <sys/mman.h>
#include <string.h>
#include <stdint.h>
intptr_t get_libc_base(pid_t pid) {
intptr_t libcAddr;
char* buf;
char* end;
FILE* fd = fopen("/proc/self/maps", "r");
if(!fd) {
printf("open maps error!");
exit(1);
}
buf = (char*) malloc(0x100);
do {
fgets(buf, 0x100, fd);
} while(!strstr(buf, "libc-"));
end = strchr(buf, '-');
libcAddr = strtol(buf, &end, 16);
// printf("The process %d's libcbase is: 0x%lx\n", pid, libcAddr);
fclose(fd);
return libcAddr;
}
intptr_t get_target_addr(intptr_t libc_base, const char* func_name) {
intptr_t funcAddr;
funcAddr = (size_t)dlsym(0, func_name);
funcAddr -= get_libc_base(getpid());
funcAddr += libc_base;
// printf("function %s address is: 0x%lx\n", func_name, funcAddr);
return funcAddr;
}
int get_asm_len(intptr_t target) {
csh handle;
cs_insn* insn;
size_t count;
char code[30] = {0};
int rv;
memcpy((void*)code, (void*)target, 30);
if(cs_open(CS_ARCH_X86, CS_MODE_64, &handle))
{
printf("Error: cs_open\n");
return -1;
}
count = cs_disasm(handle, code, 30, 0, 0, &insn);
if(count)
{
for(size_t i = 0; i < count; i++)
{
if (insn.address >= 14)
{
rv = insn.address;
break;
}
}
cs_free(insn, count);
}
else
{
printf("Error: cs_disasm\n");
return -1;
}
cs_close(&handle);
return rv;
}
// replace few bytes
void change_bytes(intptr_t addr, const char code[], int len)
{
memcpy((void*)addr, code, len);
}
void func_hook(const char* funcname, void* hook_func, void** origin_func)
{
intptr_t libc_base = get_libc_base(getpid());
intptr_t target_addr = get_target_addr(libc_base, funcname);
intptr_t page_start = target_addr & 0xfffffffff000;
mprotect((void*)page_start, 0x1000, PROT_READ|PROT_WRITE|PROT_EXEC);
int asm_len = get_asm_len(target_addr);
if(asm_len <= 0)
{
printf("Error: get_asm_len\n");
exit(-1);
}
char* temp_func = (char*)mmap(NULL, 4096, PROT_WRITE|PROT_EXEC|PROT_READ, MAP_ANON|MAP_PRIVATE, -1, 0);
memcpy((void*)temp_func, (void*)target_addr, asm_len);
intptr_t y = (intptr_t)target_addr + asm_len;
//build push&ret jump
char jmp_code[14] = {0x68,y&0xff,(y&0xff00)>>8,(y&0xff0000)>>16,(y&0xff000000)>>24,
0xC7,0x44,0x24,0x04,(y&0xff00000000)>>32,(y&0xff0000000000)>>40,(y&0xff000000000000)>>48,
(y&0xff00000000000000)>>56,0xC3};
memcpy((void*)(temp_func+asm_len), (void*)jmp_code, 14);
*origin_func = (void*)temp_func;
intptr_t x = (intptr_t)hook_func;
char hard_code[14] = {0x68,x&0xff,(x&0xff00)>>8,(x&0xff0000)>>16,(x&0xff000000)>>24,
0xC7,0x44,0x24,0x04,(x&0xff00000000)>>32,(x&0xff0000000000)>>40,(x&0xff000000000000)>>48,
(x&0xff00000000000000)>>56,0xC3};
change_bytes(target_addr, hard_code, 14);
}
static FILE* (*origin_fopen)(const char* filename, const char* mod);
static int (*origin_fclose)(FILE* fp);
static FILE* fopen_hook(const char* filename, const char* mod)
{
FILE* rv = origin_fopen(filename, mod);
printf("fopen(\"%s\", \"%s\")\n\treturn: %p\n", filename, mod, rv);
return rv;
}
static int fclose_hook(FILE* fp) {
int rv = origin_fclose(fp);
printf("fclose(%p)\n\treturn: %d\n", fp, rv);
return rv;
}
int main() {
func_hook("fopen", (void*)fopen_hook, (void**)&origin_fopen);
func_hook("fclose", (void*)fclose_hook, (void**)&origin_fclose);
FILE* file = fopen("breached.io", "r");
if (file != NULL)
{
fclose(file);
}
return 0;
}
Well, I know it's quite long, but I've explained most of them.....
## GOBAL HOOK
For now we can just hook the functions in our process, seems useless. We need to compile it to a so file and inject it to other programs.
Add these few line of code and delete main():
__attribute__((constructor))
void load()
{
func_hook("fopen", (void*)fopen_hook, (void**)&origin_fopen);
func_hook("fclose", (void*)fclose_hook, (void**)&origin_fclose);
printf("inject suceessfully\n");
}
These code will be execute whenever the so is loaded.
use this command to compile it:
gcc -shared -fPIC libhook.c -o libhook.so -ldl -lcapstone
FIND A SO INJECTOR ON GITHUB AND INJECT OUR SO.(Easy part, if you have difficulty doing this, well, you should get a better understanding of linux system~ not offensive)
All in all, thank you guys for watching this tutorial. If you think this is a good shit, leave a reply and a like. Or if you think this thing sucks, PLEASE TELL ME AND I WILL IMPROVE!!!!!