Golang LD_PRELOAD挂钩SSL_read和SSL_write

时间:2016-05-27 13:03:02

标签: ssl go openssl cgo ld-preload

失望,我对Golang很新,因为我使用以下文章作为此https://blog.gopheracademy.com/advent-2015/libc-hooking-go-shared-libraries/的基础

我正在尝试编写一个LD_PRELOAD库来拦截对OpenSSL库的SSL_read和SSL_write的调用。

这是我到目前为止提出的代码:

package main

import (
    "C"

    "log"
    "fmt"

    "github.com/rainycape/dl"
)


// main is required to build a shared library, but does nothing
func main() {}

//export SSL_read
func SSL_read(s C.int, b []byte, i C.int) C.int{

    lib, err := dl.Open("libssl", 0)
    if err != nil {
        log.Fatalln(err)
    }
    defer lib.Close()

    var oldSSL_read func(s C.int, b []byte, i C.int) C.int
    lib.Sym("SSL_read", &oldSSL_read)

    res := oldSSL_read(s, b, i)

    //buf := *(*[]byte)(b) 

    //fmt.Println(i)

    return res
}

/*
//export SSL_write
func SSL_write(){

}
*/

我正在用这种方式编译代码:

>$ go build -buildmode=c-shared -o preload.so golang_preload.g

使用openssl s_client进行测试:

LD_PRELOAD=./preload.so openssl s_client -host www.google.com -port 443

然而,这是由它引起的错误:

fatal error: unexpected signal during runtime execution
[signal 0xb code=0x1 addr=0x4 pc=0x7f1d91bdeee9]

runtime stack:
runtime.throw(0x7f1d92964580, 0x2a)
    /usr/lib/go/src/runtime/panic.go:530 +0x92
runtime.sigpanic()
    /usr/lib/go/src/runtime/sigpanic_unix.go:12 +0x5e

goroutine 17 [syscall, locked to thread]:
runtime.cgocall(0x7f1d926d4f30, 0xc82003e930, 0xc800000000)
    /usr/lib/go/src/runtime/cgocall.go:123 +0x121 fp=0xc82003e8e0 sp=0xc82003e8b0
github.com/rainycape/dl._Cfunc_call(0x7f1d9231e970, 0xc82008c160, 0xc8200762a0, 0x3, 0xc82008a038, 0xc800000000)
    github.com/rainycape/dl/_obj/_cgo_gotypes.go:83 +0x43 fp=0xc82003e930 sp=0xc82003e8e0
github.com/rainycape/dl.makeTrampoline.func1(0xc82008e280, 0x3, 0x3, 0x0, 0x0, 0x0)
    /home/asm/gocode/src/github.com/rainycape/dl/trampoline.go:124 +0x8b6 fp=0xc82003ebf8 sp=0xc82003e930
reflect.callReflect(0xc82008c120, 0xc82003edf0)
    /usr/lib/go/src/reflect/value.go:508 +0x2cd fp=0xc82003edd8 sp=0xc82003ebf8
reflect.makeFuncStub(0xc8025cec30, 0x4, 0x25c5b70, 0x25c3b60, 0xc8025c3b60, 0x0, 0x0, 0xc820076260, 0xc82008a030, 0x0, ...)
    /usr/lib/go/src/reflect/asm_amd64.s:17 +0x38 fp=0xc82003edf0 sp=0xc82003edd8
main.SSL_read(0x25cec30, 0x4, 0x25c5b70, 0x25c3b60, 0x7f1d025c3b60, 0xc800000000)
    /tmp/golang_preload.go:44 +0x1e5 fp=0xc82003ee88 sp=0xc82003edf0
main._cgoexpwrap_24df11e45e4b_SSL_read(0x25cec30, 0x4, 0x25c5b70, 0x25c3b60, 0x25c3b60, 0x25c3b60)
    command-line-arguments/_obj/_cgo_gotypes.go:68 +0x47 fp=0xc82003eec0 sp=0xc82003ee88
runtime.call64(0x0, 0x7fffb5954988, 0x7fffb5954a10, 0x30)
    /usr/lib/go/src/runtime/asm_amd64.s:473 +0x40 fp=0xc82003ef08 sp=0xc82003eec0
runtime.cgocallbackg1()
    /usr/lib/go/src/runtime/cgocall.go:267 +0x110 fp=0xc82003ef40 sp=0xc82003ef08
runtime.cgocallbackg()
    /usr/lib/go/src/runtime/cgocall.go:180 +0xd9 fp=0xc82003efa0 sp=0xc82003ef40
runtime.cgocallback_gofunc(0x0, 0x0, 0x0)
    /usr/lib/go/src/runtime/asm_amd64.s:716 +0x5d fp=0xc82003efb0 sp=0xc82003efa0
runtime.goexit()
    /usr/lib/go/src/runtime/asm_amd64.s:1998 +0x1 fp=0xc82003efb8 sp=0xc82003efb0

goroutine 34 [syscall, locked to thread]:
runtime.goexit()
    /usr/lib/go/src/runtime/asm_amd64.s:1998 +0x1

在SSL_read函数中访问缓冲区的正确方法是什么,我尝试unsafe.Pointer但我无法将类型绑定到值错误。

更新

SSL结构在openssl.h中定义。添加该导入会导致与SSL_read函数冲突。

在纯C代码中,使用简单的void*指针就足够了,用SSL替换为unsafe.Pointer,缓冲区导致以下错误:

panic: can't bind value of type unsafe.Pointer

goroutine 17 [running, locked to thread]:
panic(0x7f0a8e933400, 0xc820096060)
    /usr/lib/go/src/runtime/panic.go:464 +0x3ea
github.com/rainycape/dl.makeTrampoline.func1(0xc8200980f0, 0x3, 0x3, 0x0, 0x0, 0x0)
    /home/asm/gocode/src/github.com/rainycape/dl/trampoline.go:116 +0x186e
reflect.callReflect(0xc82009c040, 0xc82004be10)
    /usr/lib/go/src/reflect/value.go:508 +0x2cd
reflect.makeFuncStub(0xa12bd0, 0xa07b00, 0x400, 0x7f0a8e907800, 0xc82009a000, 0x0, 0x0, 0xc820096000, 0xc82009a000, 0x0, ...)
    /usr/lib/go/src/reflect/asm_amd64.s:17 +0x38
main.SSL_read(0xa12bd0, 0xa07b00, 0xc800000400, 0x7f0a00000000)
    /tmp/preload.go:26 +0x1cd
main._cgoexpwrap_613180a44973_SSL_read(0xa12bd0, 0xa07b00, 0x400, 0xa07b00)
    command-line-arguments/_obj/_cgo_gotypes.go:50 +0x35

1 个答案:

答案 0 :(得分:2)

[]byte是Go切片,您不能在C中使用。SSL_read的签名是:

SSL_read(SSL *ssl, void *buf, int num)

我命令调用工作,您需要匹配签名并在函数定义中使用等效类型。

func SSL_read(ssl *C.SSL, buf unsafe.Pointer, num C.int)