1. Ptrace basis

Long ptrace(enum __ptrace_request request, pid_t PID,void *addr,void *data);

PTRACE_ATTACH indicates attaching to the specified remote process. PTRACE_DETACH indicates separating from the specified remote process. PTRACE_GETREGS indicates reading the current register environment of the remote process. Set the remote process register environment PTRACE_CONT, to enable the remote process to continue running PTRACE_PEEKTEXT, read a word size data from the remote process specified memory address PTRACE_POKETEXT, write a word size data to the remote process specified memory address

PTRACE_ATTACH and PTRACE_DETACH apply the two parameters in injection requirements

Parameter two requires additional injected PID data

Parameter 3 and parameter 4 can be filled with NULL directly

2. Step of pTrace injection

1. Call ptrace system function to attach to remote process 2. Save register environment data 3. Allocate memory space by calling mMAP system function 4. Want additional process to write module name and function name 5. Call dlopen system function to open the injected module 6. Call DLSYm system function to obtain the address information of the function to be called 7. 8. Restore the environment data in the register. 9. Call the ptrace system function to strip from the attached process

3. Ptrace injection source implementation

3.1 Adding Processes

/ * * * * * * * * * * * * * * * * * * * n function function: using ptrace function Attach to the specified remote process parameters: the ID return value of pid said remote processes: return 0 indicates the Attach successfully, return 1 failure * * * * * * * * * * * * * * * * * * * * /  
int ptrace_attach(pid_t pid)    
{
	int status = 0;
	
    if (ptrace(PTRACE_ATTACH, pid, NULL.0) < 0) {    
        LOGD("attach process error, pid:%d", pid);    
        return - 1;    
    }    
	
 	LOGD("attach process pid:%d", pid);          
    waitpid(pid, &status , WUNTRACED);       	
    
    return 0;    
} 
Copy the code

3.2 Stripping Process

/ * * * * * * * * * * * * * * * * * * n function function: using ptrace DETACH () function to the stripping process parameters: the ID return value of pid said remote processes: returns 0 said DETACH success, return 1 failure * * * * * * * * * * * * * * * * * * /    
int ptrace_detach(pid_t pid)    
{    
    if (ptrace(PTRACE_DETACH, pid, NULL.0) < 0) {    
        LOGD("detach process error, pid:%d", pid);     
        return - 1;    
    }    
    
	LOGD("detach process pid:%d", pid);  
    return 0;    
}
Copy the code

3.2 Inject so function into PTrace

/ * * * * * * * * * * * * * * * * * * * * * * * * * * function function: the method of directly by remote calls dlopen, dlsym ptrace injection so module to the remote process parameter 1: LibPath: specifies the path of the so module to be injected remotely. FunctionName: specifies the name of the function to be called after the remote injection. FuncParameter refers to the parameters of the function being called remotely (if a string is passed, the string needs to be written to the remote process space first), NumParameter refers to the number of parameters Return: If 0 is returned, the injection succeeds. If -1 is returned, the injection fails **********************/ 
int inject_remote_process(pid_t pid, char *LibPath, char *FunctionName, long *FuncParameter, long NumParameter)
{
	int iRet = - 1;
	struct pt_regs CurrentRegs.OriginalRegs;  CurrentRegs indicates the current register value in the remote process. OriginalRegs stores the register value before injection for easy recovery
	void *mmap_addr, *dlopen_addr, *dlsym_addr, *dlclose_addr, *dlerror_addr;   // The address of the function to be called in the remote process
	void *RemoteMapMemoryAddr, *RemoteModuleAddr, *RemoteModuleFuncAddr; // RemoteMapMemoryAddr is the base address of the memory mapped in the remote process space, RemoteModuleAddr is the base address of the remote injection so module, RemoteModuleFuncAddr is the address of the function that needs to be called in the injection module
	long parameters[6];  
	
	// Attach remote process
	if (ptrace_attach(pid) == - 1)
		return iRet;
	
	// Get the remote process register value
	if (ptrace_getregs(pid, &CurrentRegs) == - 1)
	{
		ptrace_detach(pid);
		return iRet;
	}

	
	// Save the current context register environment in remote process space
	memcpy(&OriginalRegs, &CurrentRegs, sizeof(CurrentRegs)); 
	
	// Get the address of the mmap function in the remote process
	mmap_addr = GetRemoteFuncAddr(pid, libc_path, (void *)mmap);
	LOGD("mmap RemoteFuncAddr:0x%lx", (long)mmap_addr);
	
	// Set the parameters of mmap
	// void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offsize);
    parameters[0] = 0;  // Set to NULL to allow the system to automatically select an address for allocating memory
    parameters[1] = 0x1000; // Map the size of memory
    parameters[2] = PROT_READ | PROT_WRITE | PROT_EXEC;  // Indicates that the mapped memory region can be read, written and executed
    parameters[3] =  MAP_ANONYMOUS | MAP_PRIVATE; // Create an anonymous mapping
    parameters[4] = 0; // If the file needs to be mapped to memory, this is the fd of the file
    parameters[5] = 0; // File mapping offset
	
	// Create a memory map for the remote process by calling the remote process mmap function
	if (ptrace_call(pid, (long)mmap_addr, parameters, 6, &CurrentRegs) == - 1)
	{
		LOGD("Call Remote mmap Func Failed");
		ptrace_detach(pid);
		return iRet;
	}
	
	// Get the return value of the mmap function, which is the starting address of the memory map
	RemoteMapMemoryAddr = (void *)ptrace_getret(&CurrentRegs);
	LOGD("Remote Process Map Memory Addr:0x%lx", (long)RemoteMapMemoryAddr);
	
	// Obtain the addresses of dlopen, dlSYm, dlclose, etc
	dlopen_addr = GetRemoteFuncAddr(pid, linker_path, (void *)dlopen);
	dlsym_addr = GetRemoteFuncAddr(pid, linker_path, (void *)dlsym);
	dlclose_addr = GetRemoteFuncAddr(pid, linker_path, (void *)dlclose);
	dlerror_addr = GetRemoteFuncAddr(pid, linker_path, (void *)dlerror);
	

	
	// Write the path of the so library to be loaded to the remote process memory space
	if (ptrace_writedata(pid, RemoteMapMemoryAddr, LibPath, strlen(LibPath) + 1) = =- 1)
	{
		
		ptrace_detach(pid);
		return iRet;
	}
	
	// Set the parameters of dlopen and return the address where the module was loaded
	// void *dlopen(const char *filename, int flag);
	parameters[0] = (long)RemoteMapMemoryAddr;
	parameters[1] = RTLD_NOW| RTLD_GLOBAL;
	
	if (ptrace_call(pid, (long)dlopen_addr, parameters, 2, &CurrentRegs) == - 1)
	{
		
		ptrace_detach(pid);
		return iRet;
	}

	// RemoteModuleAddr Loads the address of the injection module for the remote process
	RemoteModuleAddr = (void *)ptrace_getret(&CurrentRegs);

	
	if ((long)RemoteModuleAddr == 0x0)   / / dlopen error
	{
		LOGD("dlopen error");
		if (ptrace_call(pid, (long)dlerror_addr, parameters, 0, &CurrentRegs) == - 1)
		{
			LOGD("Call Remote dlerror Func Failed");
			ptrace_detach(pid);
			return iRet;
		}
		char *Error = (void *)ptrace_getret(&CurrentRegs);
		char LocalErrorInfo[1024] = {0};
		ptrace_readdata(pid, Error, LocalErrorInfo, 1024);
		ptrace_detach(pid);
		return iRet;
	}	
	
	// Write the names of functions to be called from the so library to the remote process memory space
	if (ptrace_writedata(pid, RemoteMapMemoryAddr + strlen(LibPath) + 2, FunctionName, strlen(FunctionName) + 1) = =- 1)
	{
		
		ptrace_detach(pid);
		return iRet;
	}
	
	// Set the parameters of dlSYm and return the address of the remote in-process function
	// void *dlsym(void *handle, const char *symbol);
	parameters[0] = (long)RemoteModuleAddr;
	parameters[1] = (long)(RemoteMapMemoryAddr + strlen(LibPath) + 2);
	
	if (ptrace_call(pid, (long)dlsym_addr, parameters, 2, &CurrentRegs) == - 1)
	{
		LOGD("Call Remote dlsym Func Failed");
		ptrace_detach(pid);
		return iRet;
	}	
	
	// RemoteModuleFuncAddr is the address of the function fetched in the remote process space
	RemoteModuleFuncAddr = (void *)ptrace_getret(&CurrentRegs);
	
	
	if (ptrace_call(pid, (long)RemoteModuleFuncAddr, FuncParameter, NumParameter, &CurrentRegs) == - 1)
	{
		LOGD("Call Remote injected Func Failed");
		ptrace_detach(pid);
		return iRet;
	}	
	
	if (ptrace_setregs(pid, &OriginalRegs) == - 1)
	{
		LOGD("Recover reges failed");
		ptrace_detach(pid);
		return iRet;		
	}
	
	ptrace_getregs(pid, &CurrentRegs);
	if (memcmp(&OriginalRegs, &CurrentRegs, sizeof(CurrentRegs)) ! =0)
	{
		LOGD("Set Regs Error");
	}
	
	/ / stripping
	if (ptrace_detach(pid) == - 1)
	{
		LOGD("ptrace detach failed");
		return iRet;
	}
	
	return 0;
}
Copy the code