Linux C library piling technology

1 Introduction

Library piling technology can intercept calls to shared library functions. In application, you can control the input and output values ​​of function calls, replace function calls with your own logic, etc.;
basic idea: create a wrapper function with the same prototype as the target function, through the search mechanism implemented by the compile-time function, or the function symbol at link time Analyze the search mechanism or the loading mechanism of the dynamic link library at runtime, and replace the target function with the custom wrapper function.

2. Test environment

System environment: Ubuntu14.04
Gcc version: gcc version 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04.4)

3. Piling at compile time

3.1. Related documents

3.1.1.main.c

#include <stdio.h> 
#include <malloc.h>
int main()
{
    
    
	size_t len = 10;
	char * msg =  calloc(1,len);

	snprintf( msg,len,"%s","aloha");
	printf("msg:%s\n",msg);

	free(msg);
	msg = 0;

	return 0;
}

3.1.2.newcalloc.h

#define  calloc(nmemb,size) newcalloc(nmemb,size)
#define free(ptr)   newfree(ptr)

void *newcalloc(size_t nmemb, size_t size);
void newfree(void *ptr);

3.1.3.newcalloc.c

#include <stdio.h>
#include <malloc.h>

 void *newcalloc(size_t nmemb, size_t size)
 {
    
    

 	static int _newcalloc_calltime = 0;
 	++_newcalloc_calltime;
 	printf("calloc ptr(%d,%d) ,call times=%d\n",nmemb,size,_newcalloc_calltime);

 	void * ptr = calloc( nmemb,size);
 	printf("calloc return=%p\n",ptr);
 	return ptr;
 }


 void newfree(void *ptr)
 {
    
    
 	static int _newfree_calltime = 0;
 	++_newfree_calltime;
 	free(ptr);
 	printf("free(%p),call times =%d\n",ptr,_newfree_calltime);
 } 

3.2. Compile command

gcc -m32 -g -c newcalloc.c;
gcc -m32 -g -I. -o main main.c newcalloc.o;
./main
Note: From the test situation, the -I compile option is not specified here, and you can press Expect to run, that is, even if included in angle brackets in main.c, it is searched from the current directory first.

3.3. Running status and running commands

calloc ptr(1,10) ,call times=1
calloc return=0x8734008
msg:aloha
free(0x8734008),call times =1
Insert picture description here

3.4. Description

1. Stubbing during compilation requires access to the source code. Essentially, you first define your own packaging function, call standard target methods in the packaging function, and generate relocatable files. Then define a header file converted by macro definition (the name is the same as the header file where the function to be piling is located). When gcc is compiled, the header file with the same name is first searched locally and the wrapper function is called;
2. Here is a point to note, for The compilation of the package file newcalloc.c needs to be compiled separately, and cannot be compiled in the same directory as the header file for macro definition conversion, otherwise it will become a loop nested recursive call, which will eventually cause a program exception.

4. Piling at compile time

4.1. Related documents

4.1.1.main.c

#include <stdio.h> 
#include <malloc.h>
int main()
{
    
    
	size_t len = 10;
	char * msg =  calloc(1,len);

	snprintf( msg,len,"%s","aloha");
	printf("msg:%s\n",msg);

	free(msg);
	msg = 0;

	return 0;
}

4.1.2.newcalloc.c

#include <stdio.h>
//#include <stdlib.h> 
 void * __real_calloc(size_t nmemb, size_t size);
 void __real_free(void *ptr);


 void * __wrap_calloc(size_t nmemb, size_t size)
 {
    
    

 	static int _newcalloc_calltime = 0;
 	++_newcalloc_calltime;
 	printf("calloc ptr(%d,%d) ,call times=%d\n",nmemb,size,_newcalloc_calltime);

 	void * ptr = __real_calloc( nmemb,size);
 	printf("calloc return=%p\n",ptr);
 	return ptr;
 }


 void __wrap_free(void *ptr)
 {
    
    
 	static int _newfree_calltime = 0;
 	++_newfree_calltime;
 	__real_free(ptr);
 	printf("free(%p),call times =%d\n",ptr,_newfree_calltime);
 } 

4.2. Compile command and run command

gcc -m32 -g -c newcalloc.c;
gcc -m32 -g -c main.c;
gcc -m32 -Wl,–wrap,calloc -Wl,–wrap,free -o main main.o newcalloc.o;
./main

4.3. Operation

calloc ptr(1,10) ,call times=1
calloc return=0x840b008
msg:aloha
free(0x840b008),call times =1
Insert picture description here

4.4. Description

1. Piling during compilation requires access to relocatable object files;
2. The static linker supports piling with the -wrap f option, that is, parsing references to symbol f into __wrap_f, and parsing references to symbol __real_f Into f.

5. Piling during operation

5.1. Related documents

5.1.1.main.c

#include <stdio.h> 
#include <malloc.h>
int main()
{
    
    
	size_t len = 10;
	char * msg =  calloc(1,len);

	snprintf( msg,len,"%s","aloha");
	printf("msg:%s\n",msg);

	free(msg);
	msg = 0;

	return 0;
}

5.1.2.newcalloc.c

#include <stdio.h>
#include <stdlib.h>  

#define __USE_GNU
#include <dlfcn.h>

//#define _GNU_SOURCE
 void * calloc(size_t nmemb, size_t size)
 {
    
    

 	 void * (*callocp)(size_t nmemb, size_t size);
 	 char * error;
 	 callocp = dlsym(RTLD_NEXT,"calloc");
 	 if((error=dlerror())!=NULL)
 	 {
    
    
 	 	printf("dlsym calloc error,msg:%s\n",error);
 	 	exit(1);
 	 }
 	static int _newcalloc_calltime = 0;
 	++_newcalloc_calltime;
 	printf("calloc ptr(%d,%d) ,call times=%d\n",nmemb,size,_newcalloc_calltime);

 	void * ptr = callocp( nmemb,size);
 	printf("calloc return=%p\n",ptr);
 	return ptr;
 }


 void free(void *ptr)
 {
    
    
 	void (*freep)(void *ptr);
 	 char * error;
 	 freep = dlsym(RTLD_NEXT,"free");

 	static int _newfree_calltime = 0;
 	++_newfree_calltime;
 	freep(ptr);
 	printf("free(%p),call times =%d\n",ptr,_newfree_calltime);
 } 

5.2. Compile command and run command

gcc -m32 -g -shared -fpic -o newcalloc.so newcalloc.c -ldl;
gcc -m32 -g -o main main.c;
LD_PRELOAD="./newcalloc.so" ./main

5.3. Operation

calloc ptr(1,10) ,call times=1
calloc return=0x8fb5008
msg:aloha
free(0x8fb5008),call times =1
Insert picture description here

5.4. Description

1. This mechanism is based on the LD_RELOAD environment variable of the dynamic linker. When loading and executing a program and need to resolve undefined references, the dynamic linker (LD-LINUX.SO) will first search for the LD_PRELOAD library, and if it is not found, it will search for other libraries.
2. The macro definition _GNU_SOURCE does not work. To view the dlfcn.h file, you need to use __USE_GNU (#include <dlfcn.h> defined earlier)
Insert picture description here

6. References

"In-depth understanding of computer systems" Chinese version, [America] Randal E. Bryant waiting, 2019.3, Machinery Industry Press

Guess you like

Origin blog.csdn.net/skytering/article/details/106065262