基于的工作:Hooking libc using Go shared libraries
先把 socket() 的 libc 调用拦截下来
package main
// #cgo LDFLAGS: -ldl
// #include <stddef.h>
// #include <netinet/in.h>
// #include "network_hook.h"
import "C"
import (
"fmt"
"syscall"
)
func init() {
C.libc_hook_init()
}
//export socket
func socket(domain C.int, type_ C.int, protocol C.int) C.int {
fmt.Println(fmt.Sprintf("open socket from thread id: %v", syscall.Gettid()))
return C.orig_socket(domain, type_, protocol)
}
func main() {
}
把这个编译成 so
go build -buildmode=c-shared -o libmotrix.so main.go
然后调用
LD_PRELOAD=libmotrix.so curl http://www.baidu.com
就会把 socket 的 lib 调用给拦截下来
把 socket() 透明转交给 libc
network_hook.h
#ifndef __DLSYM_WRAPPER_H__
#define __DLSYM_WRAPPER_H__
void libc_hook_init();
int orig_socket(int, int, int);
#endif
network_hook.c
#include <dlfcn.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <netdb.h>
#include <math.h>
#include "network_hook.h"
#include "_cgo_export.h"
#define RTLD_NEXT ((void *) -1l)
#define HOOK_SYS_FUNC(name) if( !orig_##name##_func ) { orig_##name##_func = (name##_pfn_t)dlsym(RTLD_NEXT,#name); }
typedef int (*socket_pfn_t)(int, int, int);
static socket_pfn_t orig_socket_func;
void libc_hook_init() {
HOOK_SYS_FUNC( socket );
}
int orig_socket(int domain, int type, int protocol) {
return orig_socket_func(domain, type, protocol);
}
其中
- orig_socket 是函数暴露给 golang 调用
- orig_socket_func 是函数指针,指向了libc的原来的实现
- socket_pfn_t 是socket()这个函数指针的类型定义
原来文章里的实现在我的机器上报错,原因未知。感觉这样用 cgo 包装一下更简单直接一些,还少了一次反射。