Начните с документации команды Go cgo.
Команда cgo
Использование cgo с командой go
Чтобы использовать cgo, напишите обычный код Go, который импортирует псевдопакет "C".Затем код Go может ссылаться на такие типы, как C.size_t, переменные, такие как C.stdout, или функции, такие как C.putchar.
Если импорту «C» предшествует комментарий, тоКомментарий, называемый преамбулой, используется в качестве заголовка при компиляции C-частей пакета.Например:
// #include <stdio.h>
// #include <errno.h>
import "C"
Преамбула может содержать любой код на C, включая объявления и определения функций и переменных.Затем они могут быть переданы из кода Go, как если бы они были определены в пакете «C».Могут использоваться все имена, объявленные в преамбуле, даже если они начинаются со строчной буквы.Исключение: на статические переменные в преамбуле нельзя ссылаться из кода Go;разрешены статические функции.
См. примеры $ GOROOT / misc / cgo / stdio и $ GOROOT / misc / cgo / gmp.Смотрите "C? Go? Cgo!"для введения в использование cgo: https://golang.org/doc/articles/c_go_cgo.html.
CFLAGS, CPPFLAGS, CXXFLAGS, FFLAGS и LDFLAGS могут быть определены с помощью директив pseudo #cgo в этих комментариях, чтобы настроить поведение компилятора C, C ++ или Fortran.Значения, определенные в нескольких директивах, объединяются вместе.Директива может включать список ограничений сборки, ограничивающих ее действие системами, удовлетворяющими одному из ограничений (подробности о синтаксисе ограничений см. В https://golang.org/pkg/go/build/#hdr-Build_Constraints).Например:
// #cgo CFLAGS: -DPNG_DEBUG=1
// #cgo amd64 386 CFLAGS: -DX86=1
// #cgo LDFLAGS: -lpng
// #include <png.h>
import "C"
В частности:
Чтобы использовать cgo, напишите обычный код Go, который импортирует псевдопакет "C".
Если импорту "C" непосредственно предшествует комментарий, этот комментарий, называемый преамбулой, используется в качестве заголовка при компиляции частей пакета C. Все значения
CFLAGS могут быть определены с помощью псевдоДирективы #cgo в этих комментариях настраивают поведение компилятора C.
Для вашего примера:
/*
#cgo CFLAGS: -g -O3 -fno-stack-protector
#include "test.h"
*/
import "C"
Вывод (не обнаружено разрушения стека):
$ go build -a poc.go && ./poc
Go: BORING
AAAAAAAAAAAAAAA
C: 16 bytes read. Content: AAAAAAAAAAAAAAA
!
fatal error: unexpected signal during runtime execution
[signal SIGSEGV: segmentation violation code=0x1 addr=0xa41414141 pc=0xa41414141]
runtime stack:
runtime.throw(0x4bb802, 0x2a)
/home/peter/go/src/runtime/panic.go:608 +0x72
runtime.sigpanic()
/home/peter/go/src/runtime/signal_unix.go:374 +0x2ec
goroutine 1 [syscall]:
runtime.cgocall(0x484e90, 0xc000052f38, 0x0)
/home/peter/go/src/runtime/cgocall.go:128 +0x5b fp=0xc000052f08 sp=0xc000052ed0 pc=0x403deb
main._Cfunc_hackme()
_cgo_gotypes.go:41 +0x41 fp=0xc000052f38 sp=0xc000052f08 pc=0x484c51
main.regular()
/home/peter/gopath/src/poc/poc.go:25 +0x62 fp=0xc000052f88 sp=0xc000052f38 pc=0x484d52
main.main()
/home/peter/gopath/src/poc/poc.go:19 +0x65 fp=0xc000052f98 sp=0xc000052f88 pc=0x484cd5
runtime.main()
/home/peter/go/src/runtime/proc.go:201 +0x1ec fp=0xc000052fe0 sp=0xc000052f98 pc=0x42928c
runtime.goexit()
/home/peter/go/src/runtime/asm_amd64.s:1340 +0x1 fp=0xc000052fe8 sp=0xc000052fe0 pc=0x450cd1
$
poc.go
:
package main
import "os"
import "fmt"
/*
#cgo CFLAGS: -g -O3 -fno-stack-protector
#include "test.h"
*/
import "C"
func main() {
if (len(os.Args) >= 2){
argsWithoutProg := os.Args[1:]
if (argsWithoutProg[0] == "admin") {
secret();
}
} else {
regular()
}
}
func regular() {
fmt.Println("Go: BORING")
C.hackme()
}
func secret() {
fmt.Println("Go: SECRET FUNC")
}
test.h
:
#include <stdint.h>
#include <stdio.h>
void hackme();
// this function is vulnerable and is used as an entrypoint to the go part
void hackme() {
char buf[3];
int r;
r = read(0, buf, 300);
printf("C: %d bytes read. Content: %s!\n", r, buf);
return;
}
Без -fno-stack-protector
:
/*
#cgo CFLAGS: -g -O3
#include "test.h"
*/
import "C"
Выход (стекобнаружено разрушение):
$ go build -a poc.go && ./poc
Go: BORING
AAAAAAAAAAAAAAA
C: 16 bytes read. Content: AAAAAAAAAAAAAAA
!
*** stack smashing detected ***: <unknown> terminated
SIGABRT: abort
PC=0x7f1c5323ee97 m=0 sigcode=18446744073709551610
$