熟悉windows的开发者知道,hook一般用于写木马,外挂。可以用来监听系统的接口,如网络,键盘,鼠标…… 今天和大家分享一下,Android使用hook案例。 在android系统中,可以使用iptables控制单个应用网络访问。在google code上有一个开源项目-droidwall就是基于iptables实现的。除了iptables可以实现控制单个应用网络访问外,还可以通过拦截应用中的connect函数,达到控制应用访问网络的目的。下面从几个方面分析android应用中connect调用流程为例来实现拦截connect实现网络禁用和ip过滤。(以下分析基于4.2源码)
1.android中网络访问流程
1)android系统中访问网络可以通过Socket.java、URL.java、HttpPost.java、HttpGet.java等关键类来访问网络资源。通过代码追踪,这些类访问网络资源最终需要通过native方式,调用linux系统下的socket函数访问网络。在android4.2源码中,java层访问网络得native方法定义在源码路径libcore/luni/src/main/java/libcore/io/Posix.java中(4.0之前的网络系统、文件系统的native方法是独立分开得,4.0之后组织在Posix.java中)。如下是Posix.java中的代码片段:
2)Posix.java中的native方法实现源码路径libcore/luni/src/main/native/libcore_io_Posix.cpp文件中,native connect方法实现代码片段如下:
有上代码可知,java层connect最终功能由linux系统connect函数实现。
2.so注入 注入源码: inject.h
inject.c
3.拦截connect库编写
在connect中,获取传入的参数ip地址,根据需要把需要禁用的ip地址改为127.0.01.以下是我测试的拦截connect函数关键代码:
shellcode.s
4.拦截connect函数功效
1)禁用应用网络访问。 2)过滤广告ip 3)禁用定位功能
以上仅个人见解,各位大牛多多指教。
1.android中网络访问流程
1)android系统中访问网络可以通过Socket.java、URL.java、HttpPost.java、HttpGet.java等关键类来访问网络资源。通过代码追踪,这些类访问网络资源最终需要通过native方式,调用linux系统下的socket函数访问网络。在android4.2源码中,java层访问网络得native方法定义在源码路径libcore/luni/src/main/java/libcore/io/Posix.java中(4.0之前的网络系统、文件系统的native方法是独立分开得,4.0之后组织在Posix.java中)。如下是Posix.java中的代码片段:
public final class Posix implements Os { Posix() { } public native FileDescriptor accept(FileDescriptor fd, InetSocketAddress peerAddress) throws ErrnoException, SocketException; public native boolean access(String path, int mode) throws ErrnoException; public native void bind(FileDescriptor fd, InetAddress address, int port) throws ErrnoException, SocketException; ...... //对应linux下的connect系统调用 public native void connect(FileDescriptor fd, InetAddress address, int port) throws ErrnoException, SocketException;
2)Posix.java中的native方法实现源码路径libcore/luni/src/main/native/libcore_io_Posix.cpp文件中,native connect方法实现代码片段如下:
static void Posix_connect(JNIEnv* env, jobject, jobject javaFd, jobject javaAddress, jint port) { sockaddr_storage ss; if (!inetAddressToSockaddr(env, javaAddress, port, &ss)) { return; } const sockaddr* sa = reinterpret_cast(&ss); (void) NET_FAILURE_RETRY(env, int, connect, javaFd, sa, sizeof(sockaddr_storage)); }
有上代码可知,java层connect最终功能由linux系统connect函数实现。
2.so注入 注入源码: inject.h
#pragma once #include#ifdef __cplusplus extern "C" { #endif int inject_remote_process( pid_t target_pid, const char *library_path, const char *function_name, void *param, size_t param_size ); int find_pid_of( const char *process_name ); void* get_module_base( pid_t pid, const char* module_name ); #ifdef __cplusplus } #endif struct inject_param_t { pid_t from_pid; } ;
inject.c
/* ============================================================================ Name : libinject.c Author : Version : Copyright : Description : Android shared library inject helper ============================================================================ */ #include#include #include #include #include #include #include #include #include #include #include #include #define ENABLE_DEBUG 1 #define PTRACE_PEEKTEXT 1 #define PTRACE_POKETEXT 4 #define PTRACE_ATTACH 16 #define PTRACE_CONT 7 #define PTRACE_DETACH 17 #define PTRACE_SYSCALL 24 #define CPSR_T_MASK ( 1u << 5 ) #define MAX_PATH 0x100 #define REMOTE_ADDR( addr, local_base, remote_base ) ( (uint32_t)(addr) + (uint32_t)(remote_base) - (uint32_t)(local_base) ) const char *libc_path = "/system/lib/libc.so"; const char *linker_path = "/system/bin/linker"; #if ENABLE_DEBUG #define DEBUG_PRINT(format,args...) \ LOGD(format, ##args) #else #define DEBUG_PRINT(format,args...) #endif int ptrace_readdata( pid_t pid, uint8_t *src, uint8_t *buf, size_t size ) { uint32_t i, j, remain; uint8_t *laddr; union u { long val; char chars[sizeof(long)]; } d; j = size / 4; remain = size % 4; laddr = buf; for ( i = 0; i < j; i ++ ) { d.val = ptrace( PTRACE_PEEKTEXT, pid, src, 0 ); memcpy( laddr, d.chars, 4 ); src += 4; laddr += 4; } if ( remain > 0 ) { d.val = ptrace( PTRACE_PEEKTEXT, pid, src, 0 ); memcpy( laddr, d.chars, remain ); } return 0; } int ptrace_writedata( pid_t pid, uint8_t *dest, uint8_t *data, size_t size ) { uint32_t i, j, remain; uint8_t *laddr; union u { long val; char chars[sizeof(long)]; } d; j = size / 4; remain = size % 4; laddr = data; for ( i = 0; i < j; i ++ ) { memcpy( d.chars, laddr, 4 ); ptrace( PTRACE_POKETEXT, pid, dest, d.val ); dest += 4; laddr += 4; } if ( remain > 0 ) { d.val = ptrace( PTRACE_PEEKTEXT, pid, dest, 0 ); for ( i = 0; i < remain; i ++ ) { d.chars[i] = *laddr ++; } ptrace( PTRACE_POKETEXT, pid, dest, d.val ); } return 0; } int ptrace_writestring( pid_t pid, uint8_t *dest, char *str ) { return ptrace_writedata( pid, dest, str, strlen(str)+1 ); } int ptrace_call( pid_t pid, uint32_t addr, long *params, uint32_t num_params, struct pt_regs* regs ) { uint32_t i; for ( i = 0; i < num_params && i < 4; i ++ ) { regs->uregs[i] = params[i]; } // // push remained params onto stack // if ( i < num_params ) { regs->ARM_sp -= (num_params - i) * sizeof(long) ; ptrace_writedata( pid, (void *)regs->ARM_sp, (uint8_t *)¶ms[i], (num_params - i) * sizeof(long) ); } regs->ARM_pc = addr; if ( regs->ARM_pc & 1 ) { /* thumb */ regs->ARM_pc &= (~1u); regs->ARM_cpsr |= CPSR_T_MASK; } else { /* arm */ regs->ARM_cpsr &= ~CPSR_T_MASK; } regs->ARM_lr = 0; if ( ptrace_setregs( pid, regs ) == -1 || ptrace_continue( pid ) == -1 ) { return -1; } waitpid( pid, NULL, WUNTRACED ); return 0; } int ptrace_getregs( pid_t pid, struct pt_regs* regs ) { if ( ptrace( PTRACE_GETREGS, pid, NULL, regs ) < 0 ) { perror( "ptrace_getregs: Can not get register values" ); return -1; } return 0; } int ptrace_setregs( pid_t pid, struct pt_regs* regs ) { if ( ptrace( PTRACE_SETREGS, pid, NULL, regs ) < 0 ) { perror( "ptrace_setregs: Can not set register values" ); return -1; } return 0; } int ptrace_continue( pid_t pid ) { if ( ptrace( PTRACE_CONT, pid, NULL, 0 ) < 0 ) { perror( "ptrace_cont" ); return -1; } return 0; } int ptrace_attach( pid_t pid ) { if ( ptrace( PTRACE_ATTACH, pid, NULL, 0 ) < 0 ) { perror( "ptrace_attach" ); return -1; } waitpid( pid, NULL, WUNTRACED ); //DEBUG_PRINT("attached\n"); if ( ptrace( PTRACE_SYSCALL, pid, NULL, 0 ) < 0 ) { perror( "ptrace_syscall" ); return -1; } waitpid( pid, NULL, WUNTRACED ); return 0; } int ptrace_detach( pid_t pid ) { if ( ptrace( PTRACE_DETACH, pid, NULL, 0 ) < 0 ) { perror( "ptrace_detach" ); return -1; } return 0; } void* get_module_base( pid_t pid, const char* module_name ) { FILE *fp; long addr = 0; char *pch; char filename[32]; char line[1024]; if ( pid < 0 ) { /* self process */ snprintf( filename, sizeof(filename), "/proc/self/maps", pid ); } else { snprintf( filename, sizeof(filename), "/proc/%d/maps", pid ); } fp = fopen( filename, "r" ); if ( fp != NULL ) { while ( fgets( line, sizeof(line), fp ) ) { if ( strstr( line, module_name ) ) { pch = strtok( line, "-" ); addr = strtoul( pch, NULL, 16 ); if ( addr == 0x8000 ) addr = 0; break; } } fclose( fp ) ; } return (void *)addr; } void* get_remote_addr( pid_t target_pid, const char* module_name, void* local_addr ) { void* local_handle, *remote_handle; local_handle = get_module_base( -1, module_name ); remote_handle = get_module_base( target_pid, module_name ); DEBUG_PRINT( "[+] get_remote_addr: local[%x], remote[%x]\n", local_handle, remote_handle ); return (void *)( (uint32_t)local_addr + (uint32_t)remote_handle - (uint32_t)local_handle ); } int find_pid_of( const char *process_name ) { int id; pid_t pid = -1; DIR* dir; FILE *fp; char filename[32]; char cmdline[256]; struct dirent * entry; if ( process_name == NULL ) return -1; dir = opendir( "/proc" ); if ( dir == NULL ) return -1; while( (entry = readdir( dir )) != NULL ) { id = atoi( entry->d_name ); if ( id != 0 ) { sprintf( filename, "/proc/%d/cmdline", id ); fp = fopen( filename, "r" ); if ( fp ) { fgets( cmdline, sizeof(cmdline), fp ); fclose( fp ); if ( strcmp( process_name, cmdline ) == 0 ) { /* process found */ pid = id; break; } } } } closedir( dir ); return pid; } int inject_remote_process( pid_t target_pid, const char *library_path, const char *function_name, void *param, size_t param_size ) { int ret = -1; void *mmap_addr, *dlopen_addr, *dlsym_addr, *dlclose_addr; void *local_handle, *remote_handle, *dlhandle; uint8_t *map_base; uint8_t *dlopen_param1_ptr, *dlsym_param2_ptr, *saved_r0_pc_ptr, *inject_param_ptr, *remote_code_ptr, *local_code_ptr; struct pt_regs regs, original_regs; extern uint32_t _dlopen_addr_s, _dlopen_param1_s, _dlopen_param2_s, _dlsym_addr_s, \ _dlsym_param2_s, _dlclose_addr_s, _inject_start_s, _inject_end_s, _inject_function_param_s, \ _saved_cpsr_s, _saved_r0_pc_s; uint32_t code_length; long parameters[10]; DEBUG_PRINT( "[+] Injecting process: %d\n", target_pid ); if ( ptrace_attach( target_pid ) == -1 ) return EXIT_SUCCESS; if ( ptrace_getregs( target_pid, ®s ) == -1 ) goto exit; /* save original registers */ memcpy( &original_regs, ®s, sizeof(regs) ); mmap_addr = get_remote_addr( target_pid, "/system/lib/libc.so", (void *)mmap ); DEBUG_PRINT( "[+] Remote mmap address: %x\n", mmap_addr ); /* call mmap */ parameters[0] = 0; // addr parameters[1] = 0x4000; // size parameters[2] = PROT_READ | PROT_WRITE | PROT_EXEC; // prot parameters[3] = MAP_ANONYMOUS | MAP_PRIVATE; // flags parameters[4] = 0; //fd parameters[5] = 0; //offset DEBUG_PRINT( "[+] Calling mmap in target process.\n" ); if ( ptrace_call( target_pid, (uint32_t)mmap_addr, parameters, 6, ®s ) == -1 ) goto exit; if ( ptrace_getregs( target_pid, ®s ) == -1 ) goto exit; DEBUG_PRINT( "[+] Target process returned from mmap, return value=%x, pc=%x \n", regs.ARM_r0, regs.ARM_pc ); map_base = (uint8_t *)regs.ARM_r0; dlopen_addr = get_remote_addr( target_pid, linker_path, (void *)dlopen ); dlsym_addr = get_remote_addr( target_pid, linker_path, (void *)dlsym ); dlclose_addr = get_remote_addr( target_pid, linker_path, (void *)dlclose ); DEBUG_PRINT( "[+] Get imports: dlopen: %x, dlsym: %x, dlclose: %x\n", dlopen_addr, dlsym_addr, dlclose_addr ); remote_code_ptr = map_base + 0x3C00; local_code_ptr = (uint8_t *)&_inject_start_s; _dlopen_addr_s = (uint32_t)dlopen_addr; _dlsym_addr_s = (uint32_t)dlsym_addr; _dlclose_addr_s = (uint32_t)dlclose_addr; DEBUG_PRINT( "[+] Inject code start: %x, end: %x\n", local_code_ptr, &_inject_end_s ); code_length = (uint32_t)&_inject_end_s - (uint32_t)&_inject_start_s; dlopen_param1_ptr = local_code_ptr + code_length + 0x20; dlsym_param2_ptr = dlopen_param1_ptr + MAX_PATH; saved_r0_pc_ptr = dlsym_param2_ptr + MAX_PATH; inject_param_ptr = saved_r0_pc_ptr + MAX_PATH; /* dlopen parameter 1: library name */ strcpy( dlopen_param1_ptr, library_path ); _dlopen_param1_s = REMOTE_ADDR( dlopen_param1_ptr, local_code_ptr, remote_code_ptr ); DEBUG_PRINT( "[+] _dlopen_param1_s: %x\n", _dlopen_param1_s ); /* dlsym parameter 2: function name */ strcpy( dlsym_param2_ptr, function_name ); _dlsym_param2_s = REMOTE_ADDR( dlsym_param2_ptr, local_code_ptr, remote_code_ptr ); DEBUG_PRINT( "[+] _dlsym_param2_s: %x\n", _dlsym_param2_s ); /* saved cpsr */ _saved_cpsr_s = original_regs.ARM_cpsr; /* saved r0-pc */ memcpy( saved_r0_pc_ptr, &(original_regs.ARM_r0), 16 * 4 ); // r0 ~ r15 _saved_r0_pc_s = REMOTE_ADDR( saved_r0_pc_ptr, local_code_ptr, remote_code_ptr ); DEBUG_PRINT( "[+] _saved_r0_pc_s: %x\n", _saved_r0_pc_s ); /* Inject function parameter */ memcpy( inject_param_ptr, param, param_size ); _inject_function_param_s = REMOTE_ADDR( inject_param_ptr, local_code_ptr, remote_code_ptr ); DEBUG_PRINT( "[+] _inject_function_param_s: %x\n", _inject_function_param_s ); DEBUG_PRINT( "[+] Remote shellcode address: %x\n", remote_code_ptr ); ptrace_writedata( target_pid, remote_code_ptr, local_code_ptr, 0x400 ); memcpy( ®s, &original_regs, sizeof(regs) ); regs.ARM_sp = (long)remote_code_ptr; regs.ARM_pc = (long)remote_code_ptr; ptrace_setregs( target_pid, ®s ); ptrace_detach( target_pid ); // inject succeeded ret = 0; exit: return ret; } int main(int argc, char** argv) { pid_t target_pid; target_pid = find_pid_of("/system/bin/servicemanager"); inject_remote_process( target_pid, "/dev/yuki/payload.so", "hook_entry", "I'm parameter!", strlen("I'm parameter!") ); }
3.拦截connect库编写
在connect中,获取传入的参数ip地址,根据需要把需要禁用的ip地址改为127.0.01.以下是我测试的拦截connect函数关键代码:
int new_connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen) { LOGDD("HOOK ====>new connect****************"); char ip[128]={0}; int port=-1; if(addr->sa_family==AF_INET) { struct sockaddr_in *sa4=(struct sockaddr_in*)addr; inet_ntop(AF_INET,(void*)(struct sockaddr*)&sa4->sin_addr,ip,128); port=ntohs(sa4->sin_port); LOGDD("AF_INET IP===>%s:%d",ip,port); } else if(addr->sa_family==AF_INET6) { struct sockaddr_in6 *sa6=(struct sockaddr_in6*)addr; char *ipv6=NULL; inet_ntop(AF_INET6,(void*)(struct sockaddr*)&sa6->sin6_addr,ip,128); ipv6=strstr(ip,"f:"); if(NULL!=ipv6) { strcpy(ip,ipv6+2); } port=ntohs(sa6->sin6_port); LOGDD("af_inet6 IP===>%s:%d",ip,port); } else { return old_connect(sockfd,addr,addrlen); } if(strcmp(ip,"115.23.20.178")==0) { LOGDD("%s ==>127.0.0.1",ip); struct sockaddr_in my_addr; int my_len=sizeof(struct sockaddr_in); bzero(&my_addr,sizeof(my_addr)); my_addr.sin_family=AF_INET; my_addr.sin_port=htons(80); my_addr.sin_addr.s_addr=inet_addr("127.0.0.1"); return old_connect(sockfd,(const sockaddr*)&my_addr,sizeof(my_addr)); } else { return old_connect(sockfd,addr,addrlen); } }
shellcode.s
.global _dlopen_addr_s .global _dlopen_param1_s .global _dlopen_param2_s .global _dlsym_addr_s .global _dlsym_param2_s .global _dlclose_addr_s .global _inject_start_s .global _inject_end_s .global _inject_function_param_s .global _saved_cpsr_s .global _saved_r0_pc_s .data _inject_start_s: @ debug loop 3: @sub r1, r1, #0 @B 3b @ dlopen ldr r1, _dlopen_param2_s ldr r0, _dlopen_param1_s ldr r3, _dlopen_addr_s blx r3 subs r4, r0, #0 beq 2f @dlsym ldr r1, _dlsym_param2_s ldr r3, _dlsym_addr_s blx r3 subs r3, r0, #0 beq 1f @call our function ldr r0, _inject_function_param_s blx r3 subs r0, r0, #0 beq 2f 1: @dlclose mov r0, r4 ldr r3, _dlclose_addr_s blx r3 2: @restore context ldr r1, _saved_cpsr_s msr cpsr_cf, r1 ldr sp, _saved_r0_pc_s ldmfd sp, {r0-pc} _dlopen_addr_s: .word 0x11111111 _dlopen_param1_s: .word 0x11111111 _dlopen_param2_s: .word 0x2 _dlsym_addr_s: .word 0x11111111 _dlsym_param2_s: .word 0x11111111 _dlclose_addr_s: .word 0x11111111 _inject_function_param_s: .word 0x11111111 _saved_cpsr_s: .word 0x11111111 _saved_r0_pc_s: .word 0x11111111 _inject_end_s: .space 0x400, 0 .end
4.拦截connect函数功效
1)禁用应用网络访问。 2)过滤广告ip 3)禁用定位功能
以上仅个人见解,各位大牛多多指教。
收藏的用户(0) X
正在加载信息~
推荐阅读
最新回复 (1)
- QQAEF347A92AAEE0F53AD54D9584160D 2015-1-14引用 2楼有用,标记一下!
站点信息
- 文章2305
- 用户1336
- 访客11455720
每日一句
Talent without working hard is nothing.
没有努力,天份不代表什么。
没有努力,天份不代表什么。
MySQL 数据库优化
This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its de
免ROOT实现模拟点击任意位置
Mobaxterm终端神器
CreateProcessW要注意的细节问题
Autonomous NAT Traversal
【教程】win10 彻底卸载edge浏览器
eclipse工程基于Xposed的一个简单Hook
排名前5的开源在线机器学习
Mac OS最简单及(Karabiner)快捷键设置
发一款C++编写的麻将
VMware NAT端口映射外网访问虚拟机linux
独家发布最新可用My-AutoPost——wordpress 采集器
新会员