http://blog.chinaunix.net/uid/16979052.html
全部博文(286)
分类: LINUX
2013-03-04 08:25:33
目录
在UNIX的动态链接库中,LD_PRELOAD环境变量可以影响程序的运行时链接(Runtime linker),它允许你定义在程序运行前优先加载的动态链接库。这个功能主要就是用来有选择性的载入不同动态链接库中的相同函数。通过这个环境变量,我们可以在主程序和其动态链接库的中间加载别的动态链接库,甚至覆盖正常的函数库。一方面,我们可以以此功能来使用自己的或是更好的函数(无需别人的源码),而另一方面,我们也可以以向别人的程序注入恶意程序。
索引关键字:UNIX, LD_PRELOAD, Socket
Linux上很多网路应用是不支持代理功能的。可以通过LD_PRELOAD环境变量使得此类TCP应用支持代理功能(实现见示例)。
Win32平他实现同样功能见TCOE稿件《使用Winsock2 SPI 实现简单Socket通讯监控》
原理:利用代理服务器对外提供的SSL PROXY功能(CONNECT方法),当应用系统对外请求TCP操作时,截获系统的connect函数方法,并在自定义的connect方法中实现连接代理,并发送"CONNECT ip:port HTTP/1.0\r\n", 当proxy服务器返回200 Ok后,表明不支持代理的应用和目标服务器已经建立了TCP连接,连接建立后其它的SOCKET函数不需要进行额外的处理了。
$export LD_PRELOAD=./proxy.so
$dig @4.2.2.2 +tcp
lib init
proxy <192.168.1.95:8080>
<4.2.2.2:53>...
<4.2.2.2:53>-OK
; <<>> DiG 9.6-ESV-R1 <<>> @4.2.2.2 +tcp
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 56862
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;. IN A
;; ANSWER SECTION:
. 300 IN A 202.107.117.5
;; Query time: 9544 msec
;; SERVER: 4.2.2.2#53(4.2.2.2)
;; WHEN: Wed Nov 24 09:27:10 2010
;; MSG SIZE rcvd: 49
例子采用gcc version 4.3.2
proxy.c(gcc -shared -fPIC proxy.c -o proxy.so -ldl) |
79 static void init()
80 {
81 get_conf(proxylist, &proxylistlen);
82 true_connect =(connect_t)dlsym(RTLD_NEXT, "connect");
83 if(!true_connect)
84 {
85 log_error("Cannot load symbols: %s", dlerror());
86 exit(1);
87 }
88 log_verbose("lib init\n");
89 blib_init = 1;
90 }
91 int connect(int sock, const struct sockaddr *addr, unsigned int len)
92 {
93 int socktype=0,flags=0,ret=0;
94 socklen_t optlen=0;
95 if(!blib_init)
96 init();
97 struct sockaddr_in* sin = (struct sockaddr_in*)addr;
98 optlen=sizeof(socktype);
99 getsockopt(sock,SOL_SOCKET,SO_TYPE,&socktype,&optlen);
100 if(!((sin->sin_family==AF_INET)&&(socktype==SOCK_STREAM)))
101 return true_connect(sock,addr,len);
102 if(sin->sin_addr.s_addr== 0x100007F)/*127.0.0.1*/
103 return true_connect(sock, addr, len);
104 flags=fcntl(sock, F_GETFL, 0);
105 if(flags & O_NONBLOCK)
106 fcntl(sock, F_SETFL, !O_NONBLOCK);
107 ret=start_proxy(sock,(struct sockaddr_in*)addr, proxylist, proxylistlen);
108 fcntl(sock, F_SETFL, flags);
109 if(ret!=0)
110 errno=ECONNREFUSED;
111 return ret;
112 }
59 static int tunnel_to(int sock, struct sockaddr_in* dst, proxy_data *pd)
60 {
61 int len;
62 char buff[BUFF_SIZE];
63 bzero(buff, sizeof(buff));
64 switch (pd->pt)
65 {
66 case HTTP_TYPE:
67 {
68 sprintf(buff,"CONNECT %s:%d HTTP/1.0\r\n", inet_ntoa(dst->sin_addr), ntohs(dst->sin_port));
69 if(pd->user[0])
70 {
71 char src[256];
72 char dst[512];
73 strcpy(src,pd->user);
74 strcat(src,":");
75 strcat(src,pd->pass);
76 encode_base_64(src,dst,strlen(src));
77 strcat(buff,"Proxy-Authorization: Basic ");
78 strcat(buff,dst);
79 strcat(buff,"\r\n\r\n");
80 }
81 else
82 strcat(buff,"\r\n");
83 len=strlen(buff);
84 if(len!=proxy_send(sock,buff,len,0))
85 return -1;
86 bzero(buff,sizeof(buff));
87 len=0;
88
while (len
89 {
90 if(1==readall(sock,buff+len,1))
91 len++;
92 else
93 return -1;
94 if(len > 4 && buff[len-1]=='\n' && buff[len-2]=='\r' && buff[len-3]=='\n' && buff[l
95 break;
96 }
97 if((len==BUFF_SIZE) || !(buff[9] =='2' && buff[10]=='0' && buff[11]=='0'))
98 return -2;
99 return 0;
100 }
101 break;
102 }
103 return -1;
104 }
216 static int timed_connect(int sock, const struct sockaddr *addr, unsigned int len)
217 {
218 int ret,value;
219 socklen_t value_len;
220 struct pollfd pfd[1];
221 pfd[0].fd=sock;
222 pfd[0].events=POLLOUT;
223 fcntl(sock, F_SETFL, O_NONBLOCK);
224 ret=true_connect(sock, addr, len);
225 if(ret==-1 && errno==EINPROGRESS)
226 {
227 ret=poll(pfd,1,tcp_connect_time_out);
228 if(ret==1)
229 {
230 value_len=sizeof(int);
231 getsockopt(sock,SOL_SOCKET,SO_ERROR,&value,&value_len);
232 if(!value)
233 ret=0;
234 else
235 ret=-1;
236 }
237 else
238 ret=-1;
239 }
240 else if(ret==0)
241 ;
242 else
243 ret=-1;
244 fcntl(sock, F_SETFL, !O_NONBLOCK);
245 return ret;
246 }
247 static int conn_proxy(int *fd, proxy_data *pd)
248 {
249 struct sockaddr_in addr;
250 *fd=socket(PF_INET,SOCK_STREAM,0);
251 if(*fd==-1)
252 return -1;
253 bzero(&addr,sizeof(addr));
254 addr.sin_family = AF_INET;
255 addr.sin_addr.s_addr = pd->ip;
256 addr.sin_port = pd->port;
257 if(timed_connect(*fd ,(struct sockaddr*)&addr,sizeof(addr)))
258 {
259 close(*fd);
260 return -1;
261 }
262 return 0;
263 }
264 int start_proxy(int sock, struct sockaddr_in* sin, proxy_data *plst, int len)
265 {
266 int proxyfd;
267 int i;
268 if(conn_proxy(&proxyfd, plst))
269 {
270 errno = ETIMEDOUT;
271 return -1;
272 }
273 log_verbose("proxy <%s:%d>\n", inet_ntoa(*(struct in_addr*)&(plst->ip)), ntohs(plst->port));
274 struct sockaddr_in addr;
275 bzero(&addr,sizeof(addr));
276 addr.sin_family = AF_INET;
277 for(i=0;i<(len-1);i++)
278 {
279 addr.sin_addr.s_addr = (plst+i+1)->ip;
280 addr.sin_port = (plst+i+1)->port;
281 if(tunnel_to(proxyfd, &addr, plst+i))
282 {
283 close(proxyfd);
284 errno = ETIMEDOUT;
285 return -1;
286 }
287 log_verbose("tunnel[%d] <%s:%d>\n", i, inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
288 }
289 log_verbose("<%s:%d>...\n", inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
290 if(tunnel_to(proxyfd, sin, plst+i))
291 {
292 close(proxyfd);
293 errno = ETIMEDOUT;
294 return -1;
295 }
296 log_verbose("<%s:%d>-OK\n", inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
297 dup2(proxyfd, sock);
298 close(proxyfd);
299 return 0;
300 }
301
|
LD_PRELOAD为UNIX平台提供了类似Win32的HOOK功能,同时为系统带来很多潜在的危机。UNIX平台很多VPN软件都采用了这种方式实现SOCKET的拦截功能。利用好LD_PRELOAD可为系统开发提供很多意想不到的功效。