Skip to content

Instantly share code, notes, and snippets.

@NSEcho
Last active December 29, 2022 19:03
Show Gist options
  • Save NSEcho/5bd1d91c9509dc14bd7d662f910078e2 to your computer and use it in GitHub Desktop.
Save NSEcho/5bd1d91c9509dc14bd7d662f910078e2 to your computer and use it in GitHub Desktop.
go runtime analysis
let Pointer = Process.pointerSize;
let syms = Process.enumerateModules()[0].enumerateSymbols();
let PCLNTAB = "runtime.pclntab"
let GOBUILDID = "go.buildid"
let GOROOTC = "runtime.defaultGOROOT.str"
let BUILDVERSIONC = "runtime.buildVersion.str"
let FIRSTMODULEDATAC = "runtime.firstmoduledata"
let GOSTRING = "go.string.*"
let TFLAGEXTRASTAR = 1 << 1
class Sym {
constructor(name, sizeOfArgs, entry) {
this.name = name;
this.sizeOfArgs = sizeOfArgs;
this.entry = entry;
}
}
let kinds = {
0:"Invalid Kind",
1:"Bool",
2:"Int",
3:"Int8",
4:"Int16",
5:"Int32",
6:"Int64",
7:"Uint",
8:"Uint8",
9:"Uint16",
10:"Uint32",
11:"Uint64",
12:"Uintptr",
13:"Float32",
14:"Float64",
15:"Complex64",
16:"Complex128",
17:"Array",
18:"Chan",
19:"Func",
20:"Interface",
21:"Map",
22:"Pointer",
23:"Slice",
24:"String",
25:"Struct",
26:"UnsafePointer"
}
class Go {
constructor() {
this.available = false;
this.pcl = null;
this.goroot = "";
this.buildVersion = "";
this.firstModuledata = "";
for (var i = 0; i < syms.length; i++) {
switch(syms[i].name) {
case GOBUILDID:
this.available = true;
break;
case GOROOTC:
this.goroot = Memory.readCString(ptr(syms[i].address))
break;
case BUILDVERSIONC:
this.buildVersion = Memory.readCString(ptr(syms[i].address));
break;
case FIRSTMODULEDATAC:
this.firstModuledata = syms[i].address;
}
}
this.available = (function() {
var av = false;
for (var i = 0; i < syms.length; i++) {
if (syms[i].name == GOBUILDID) {
av = true;
break;
}
}
return av;
})();
if (this.available) {
this.symbols = []
this.pcl = (function() {
var addr = null;
for (var i = 0; i < syms.length; i++) {
if (syms[i].name == PCLNTAB) {
addr = syms[i].address;
break;
}
}
return ptr(addr);
})();
this.nfunc = Memory.readLong(this.pcl.add(Pointer));
this.nfile = Memory.readLong(this.pcl.add(Pointer*2));
this.textStart = Memory.readLong(this.pcl.add(Pointer * 3));
this.cuOffset = Memory.readLong(this.pcl.add(Pointer*5));
this.cutab = this.pcl.add(this.cuOffset);
this.funcnameOffset = Memory.readLong(this.pcl.add(Pointer * 4));
this.filetabOffset = Memory.readLong(this.pcl.add(Pointer*6));
this.pctabOffset = Memory.readLong(this.pcl.add(Pointer*7));
this.pctab = this.pcl.add(this.pctabOffset);
this.pclnOffset = Memory.readLong(this.pcl.add(Pointer * 8));
this.pcln = this.pcl.add(this.pclnOffset);
this.funcnametab = this.pcl.add(this.funcnameOffset);
this.fileTab = this.pcl.add(this.filetabOffset);
this.functab = this.pcl.add(this.pclnOffset);
}
};
enumerateExports() {
if (!this.available) {
console.log("Binary is not built with go!");
return;
}
if (this.symbols.length == 0) {
var p = this.functab;
for (var i = 0; i < this.nfunc; i++) {
var funcAddress = Memory.readInt(p) + this.textStart;
p = p.add(4);
var funcOffset = Memory.readInt(p);
p = p.add(4);
var nameOffset = Memory.readU32(this.functab.add(funcOffset + 4));
var sizeOfArgs = Memory.readU32(this.functab.add(funcOffset + 8));
if (sizeOfArgs == 2147483648) {
sizeOfArgs = 0;
}
var name = Memory.readUtf8String(this.funcnametab.add(nameOffset));
var sym = new Sym(name, sizeOfArgs, "0x" + funcAddress.toString(16));
this.symbols.push(sym);
}
}
return this.symbols;
};
typeOfPtr() {
return "this method will return the type of pointer";
};
// returns symbols inside the filetab
readFileTabSymbols() {
var filetabStrings = []
var finished = false;
var p = go.fileTab;
while (!finished) {
var bt = Memory.readU8(p);
var peekbt = Memory.readU8(p.add(1));
if (bt == 0 && peekbt == 0) {
finished = true;
break;
}
var s = Memory.readUtf8String(p);
filetabStrings.push(s);
p = p.add(s.length+1);
}
return filetabStrings;
};
// It disassembles function that ends only with the ret
disassembleFn(fnAddr) {
var addr = ptr(fnAddr);
var inst = Instruction.parse(addr);
console.log(addr, inst.toString());
var next = inst.next;
while (next != null) {
inst = Instruction.parse(ptr(next));
console.log(inst.address, inst.toString());
if (inst.mnemonic == "ret") {
break;
}
next = inst.next;
};
};
getType(addr) {
var kind = Memory.readU8(ptr(addr).add(23)) // kind inside _type struct
switch (kinds[kind]) {
case "Struct":
case "Array":
var nm = Memory.readU32(ptr(addr).add(40)) // str inside _type struct
var tflag = Memory.readU8(ptr(addr).add(20)) // tflag inside _type struct
var types = Memory.readPointer(go.firstModuledata.add(168+8*16)) // types section holding _type structures
var off = 0;
var flagRes = tflag & TFLAGEXTRASTAR;
if (flagRes != 0) {
off = 2;
}
var typeName = Memory.readUtf8String(types.add(nm+off));
var match = /[\u0000-\u0008,\u000A-\u001F,\u007F-\u00A0]+/.exec(typeName); // remove nonprintable chars
if (match != null) {
typeName = typeName.slice(0, match.index);
}
return kinds[kind] + " => " + typeName;
break;
default:
return kinds[kind]
}
};
}
var go = new Go();
global.go = go;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment