Hello World

A sample go program is show here.

package main

import "fmt"

func main() {
  message := greetMe("world")
  fmt.Println(message)
}

func greetMe(name string) string {
  return "Hello, " + name + "!"
}

Run the program as below:

$ go run hello.go
Variables

Normal Declaration:

var msg string
msg = "Hello"

Shortcut:

msg := "Hello"
Constants
const Phi = 1.618
Strings
str := "Hello"

Multiline string

str := `Multiline
string`
Numbers

Typical types

num := 3          // int
num := 3.         // float64
num := 3 + 4i     // complex128
num := byte('a')  // byte (alias for uint8)

Other Types

var u uint = 7        // uint (unsigned)
var p float32 = 22.7  // 32-bit float
Arrays
// var numbers [5]int
numbers := [...]int{0, 0, 0, 0, 0}
Pointers
func main () {
  b := *getPointer()
  fmt.Println("Value is", b)
func getPointer () (myPointer *int) {
  a := 234
  return &a
a := new(int)
*a = 234

Pointers point to a memory location of a variable. Go is fully garbage-collected.

Type Conversion
i := 2
f := float64(i)
u := uint(i)
Slice
slice := []int{2, 3, 4}
slice := []byte("Hello")
curl https://api.openai.com/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -d '{
    "model": "gpt-3.5-turbo",
    "messages": [
      {
        "role": "system",
        "content": "You are a helpful assistant."
      },
      {
        "role": "user",
        "content": "Hello!"
      }
    ]
  }'
Condition
if day == "sunday" || day == "saturday" {
  rest()
} else if day == "monday" && isTired() {
  groan()
} else {
  work()
}
if _, err := doThing(); err != nil {
  fmt.Println("Uh oh")
Switch
switch day {
  case "sunday":
    // cases don't "fall through" by default!
    fallthrough

  case "saturday":
    rest()

  default:
    work()
}
Loop
for count := 0; count <= 10; count++ {
  fmt.Println("My counter is at", count)
}
entry := []string{"Jack","John","Jones"}
for i, val := range entry {
  fmt.Printf("At position %d, the character %s is present\n", i, val)
n := 0
x := 42
for n != x {
  n := guess()
}
Condition
if day == "sunday" || day == "saturday" {
  rest()
} else if day == "monday" && isTired() {
  groan()
} else {
  work()
}
if _, err := doThing(); err != nil {
  fmt.Println("Uh oh")
Angr

Rules:

  • EagerReturnsSimplifier
    • Adds additional return statements to the decompiled code to improve readabilit of the code, if the number of the “in edges” for the return node (i.e., in-degree of the return site) is less than a specified threshold

Core libraries:

  • SequenceWalker
    • Used to traverse graphs

For each decompiled function, angr constructs a corresponding abstract syntax tree (AST).

When angr modifies the CFG (e.g., applies EagerReturnsSim- plifier), angr calls SequenceWalker to traverse the graph and modify nodes, e.g., insert additional return statements on the AST.

Ijk_Boring is used to handle the conditional branch instruction.

Variable
NAME="John"
echo $NAME
echo "$NAME"
echo "${NAME}
Condition
if [[ -z "$string" ]]; then
  echo "String is empty"
elif [[ -n "$string" ]]; then
  echo "String is not empty"
fi
FoxDec
Freek Verbeek, Pierre Olivier, and Binoy Ravindran. Sound C code decompilation for a subset of x86-64 bi- naries. In Frank S. de Boer and Antonio Cerone, editors, Software Engineering and Formal Methods - 18th In- ternational Conference, SEFM 2020, Amsterdam, The Netherlands, September 14-18, 2020, Proceedings, vol- ume 12310 of Lecture Notes in Computer Science, pages 247–264. Springer, 2020.
Ghidra

Internally, Ghidra uses debug information, stored in the binary in the DWARF format, from binary to help recover the function prototype of the decompiled function.

For functions with the same name with different argu- ments (i.e., function overloading), compilers store multiple entities in DWARF sections. However, Ghidra may fail to match the correct entity for such a function. Consequently, Ghidra suspends the analysis of this function, which results in its decompiled function lacking arguments, i.e., void.

In Ghidra, constants are treated simi- larly to global variables, which means rules will be applied to infer their types (both their signedness and their sizes).

When Ghidra cannot correctly resolve indirect addresses, it uses the notion of partially re- solved address, as shown in this expression: “𝑣𝑎𝑟1.𝑥_𝑦 = 𝑣𝑎𝑟2”. This expression means that only 𝑦 bytes starting with offset 𝑥 in 𝑣𝑎𝑟1 should become equal to 𝑣𝑎𝑟2.

Interpreted vs Compiled

Interpreted languages

  • Implement semantics themselves
  • AST-based (recursive) interpreteers
  • Bytecode-interpreters (VM)

Compiled languages

  • Delegate semantics to a traget languages
  • Ahead-of-time (AOT) compilers
  • Just-in-time (JIT) compilers
  • AST-transformers (transpilers)