golang程序能不能用LD_PRELOAD进行hook?

初步的答案是不能。

高级一点能行的方法在最后的链接里。

golang自己实现了相关的libc里面的函数,LD_PRELOAD环境变量其实是 libc里面的功能,可以在加载函数时,优先调用 LD_PRELOAD指定的so里面的函数。

可以用以下代码进行测试:

#define _GNU_SOURCE

#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <malloc.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <errno.h>


typedef int (*orig_socket_func_type)(int domain, int type, int protocol);
typedef int (*orig_accept_func_type)(int sockfd,struct sockaddr *addr,socklen_t *addrlen);



typedef int (*orig_bind_func_type)(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
typedef int (*orig_listen_func_type)(int sockfd, int backlog);


const int DEFAULT_PRIORITY = 6;



int bind(int fd, const struct sockaddr *addr,
         socklen_t addrlen)
{
    int reuse = 1;
    int ret = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &reuse, sizeof(reuse));
    if(ret<0)
    {
         printf("setsockopt SO_REUSEPORT failed. result:%d, err:%s\n", ret, strerror(errno));
    }
    printf("listen bind ok.\n");
    

    orig_bind_func_type  orig_func;
    orig_func = (orig_bind_func_type)dlsym(RTLD_NEXT, "bind");
    return orig_func(fd, addr, addrlen);

}


int listen(int fd, int backlog)
{
    int reuse = 1;
    int ret = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &reuse, sizeof(reuse));
    if(ret<0)
    {
         printf("setsockopt SO_REUSEPORT failed. result:%d, err:%s\n", ret, strerror(errno));
    }
    printf("listen hook ok.\n");
    

    orig_listen_func_type  orig_func;
    orig_func = (orig_listen_func_type)dlsym(RTLD_NEXT, "listen");
    return orig_func(fd, backlog);

}

Makefile

CFLAGS += -std=c99 

default: prsocket.so

prsocket.so: prsocket.c
	gcc $(CFLAGS) -shared -fPIC prsocket.c -o prsocket.so -ldl


clean:
	rm *.so

运行nc ,可以看到,hook 是正常工作的。

$> LD_PRELOAD=./prsocket.so   nc -l 9000
socket hook ok.
listen bind ok.
listen hook ok.

用golang 进行测试。

最简单的http服务。 http.go

package main

import (
    "fmt"
    "net/http"
)

func main() {
    http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
        fmt.Fprint(writer, "Hello world")
    })
    server := http.Server{
        Addr: ":9091",
    }
    fmt.Println("Starting server")

    if err := server.ListenAndServe(); err != nil {
        panic(err)
    }
}
go build http.go 

LD_PRELOAD=./prsocket.so  ./http

完全没有hook上。

这个链接说可以用Rust写的程序实现对golang的hook,谁懂的可以参考一下。

文章链接:Hooking Go from Rust - Hitchhiker’s Guide to the Go-laxy MetalBear 🐻 - Tools for Backend EngineersHow did we hook Go functions from Rust to work with mirrord? A quick dive into the Go Runtime and switching from the Go stack to the system stack.https://metalbear.co/blog/hooking-go-from-rust-hitchhikers-guide-to-the-go-laxy/Golang doesn’t use libc on Linux, and instead calls syscalls directly. This is mostly harmless for the common developer - they don’t care about the assembly, syscalls, linkage, etc - they just want their binary to work. Therefore, being self-contained provides a very good user experience, as Go applications aren’t dependent on the local machine’s libc.

从作者的这个项目来看,他已经实现了对golang的hook,并且应用到了实际的应用中。

GitHub - metalbear-co/mirrord: Connect your local process and your cloud environment, and run local code in cloud conditions.Connect your local process and your cloud environment, and run local code in cloud conditions. - GitHub - metalbear-co/mirrord: Connect your local process and your cloud environment, and run local code in cloud conditions.https://github.com/metalbear-co/mirrord

其他参考资料:

ubuntu - libfaketime doesn't work with golang - Stack Overflow

Go compiler produces dynamically linked binaries by default (unless instructed otherwise). Just do ldd and you will see that the binary is linked to libc.so (tested on Linux). The difference is that the go packages it depends on, are bundled in the binary. But not the system libraries. 

– jimis

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

路边闲人2

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值