Golang LD_PRELOAD для перехвата SSL_read и SSL_write

Отказ от ответственности, я очень новичок в Golang, так как я использовал следующую статью в качестве основы для этого https://blog.gopheracademy.com/advent-2015/libc-hooking-go-shared-libraries/

Я пытаюсь написать библиотеку LD_PRELOAD, которая бы перехватывала вызовы SSL_read и SSL_write библиотеки OpenSSL.

Это код, который я придумал до сих пор:

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*, замена его на unsafe.Pointer для SSL и буфера приводит к следующей ошибке:

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

person 3asm_    schedule 27.05.2016    source источник
comment
Вы пробовали использовать uintptr?   -  person JimB    schedule 28.05.2016


Ответы (1)


[]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)
person JimB    schedule 27.05.2016
comment
спасибо, однако C.ssl не определен. Я пробовал добавить // #include ‹openssl/ssl.h›, но он все еще не распознает его - person 3asm_; 27.05.2016