Sunday, May 26, 2024

Using Reflection in Go

Have you ever been writing Go and needed to quickly find all the possible functions or fields you can use with a particular instance of a call?

Golang's built in "reflection" is a quick way to find out. A neat metaprogramming trick. For example, the following code, when used against a particular crypto library:

import ( 
	"reflect"
	"github.com/zmap/zcrypto/tls"
)
func GetJa3Hash(serverHello *tls.ServerHello) string {
    byteString := make([]byte, 0)
...

Next, we can iterate over the serverHello within our function call. I mostly use this for debugging. Essentially, reflection allows us to use a program to inspect its own source code on the fly. Consider the example below. We can iterate and print all of the fields, methods, and their corresponding types accessible from serverHello.

typ := reflect.TypeOf(*serverHello)

for i := 0; i < typ.NumField(); i++ {
	field := typ.Field(i)
	fmt.Printf("Field: %s, Type: %s\n", field.Name, field.Type)
}

for i := 0; i < typ.NumMethod(); i++ {
	method := typ.Method(i)
	fmt.Printf("Method: %s\n", method.Name)
}

And... wham. Now we have a quick list of fields we can access. For example, SessionID or HeartbeatSupported, and so on.

Field: Version, Type: tls.TLSVersion
Field: Random, Type: []uint8
Field: SessionID, Type: []uint8
Field: CipherSuite, Type: tls.CipherSuite
Field: CompressionMethod, Type: uint8
Field: OcspStapling, Type: bool
Field: TicketSupported, Type: bool
Field: SecureRenegotiation, Type: bool
Field: HeartbeatSupported, Type: bool
Field: ExtendedRandom, Type: []uint8
Field: ExtendedMasterSecret, Type: bool
Field: SignedCertificateTimestamps, Type: []tls.ParsedAndRawSCT
Field: AlpnProtocol, Type: string

No comments:

Post a Comment