Git Product home page Git Product logo

Comments (12)

mewmew avatar mewmew commented on May 22, 2024 1

@kgwinnup, wow. Quick response time :)

I started looking at it, and it seems that making it optional was quite easy. Just needed to change 5 or so lines of code. Now, I'm going about fixing a few nil-deref panics.

edit: not at all a finished patch, but this works and does make loading of apisetschema.dll optional. I also added a few log statements to handle errors where otherwise I would run into nil-deref panics.

diff --git a/windows/loader.go b/windows/loader.go
index d34b487..dd1bea0 100644
--- a/windows/loader.go
+++ b/windows/loader.go
@@ -1,6 +1,7 @@
 package windows
 
 import "fmt"
+import "log"
 import "os"
 import "bytes"
 import "strings"
@@ -377,6 +378,10 @@ func retrieveDllFromDisk(cur map[string]*pefile.PeFile, apiset *pefile.PeFile, s
 	// get realDll name on disk
 	// for apiset recurse through each real dll in the apisets list
 	if strings.Compare(name[:4], "api-") == 0 {
+		if apiset == nil {
+			fmt.Fprintf(os.Stderr, "error loading dll %s; unable to locate \"apisetschema.dll\"\n", name)
+			return
+		}
 		apiset_len := len(apiset.Apisets[name[0:len(name)-6]]) - 1
 		if apiset_len >= 0 {
 			realDll = apiset.Apisets[name[0:len(name)-6]][apiset_len]
@@ -757,11 +762,11 @@ func (emu *WinEmulator) initPe(pe *pefile.PeFile, path string, arch, mode int, a
 	}
 
 	// load Apisetschema dll for mapping to real dlls
-	apisetPath, err := util.SearchFile(emu.SearchPath, "apisetschema.dll")
-	if err != nil {
-		return err
+	var apiset *pefile.PeFile
+	if apisetPath, err := util.SearchFile(emu.SearchPath, "apisetschema.dll"); err == nil {
+		// only load apisetschema.dll if present.
+		apiset, _ = pefile.LoadPeFile(apisetPath)
 	}
-	apiset, _ := pefile.LoadPeFile(apisetPath)
 
 	// create the main map to hold all name/realdll mappings to actual PeFile object
 	peMap := make(map[string]*pefile.PeFile)
@@ -813,9 +818,11 @@ func (emu *WinEmulator) initPe(pe *pefile.PeFile, path string, arch, mode int, a
 	ldrEntry := emu.createLdrEntry(pe, 0)
 	emu.writeLdrEntry(ldrEntry, "Memory")
 	emu.writeLdrEntry(ldrEntry, "Initialization")
-	var lpe *pefile.PeFile
 	for i, key := range ldrList {
-		lpe = peMap[key]
+		lpe, ok := peMap[key]
+		if !ok {
+			log.Printf("unable to locate DLL %q", key)
+		}
 		ldrEntry = emu.createLdrEntry(lpe, uint64(i+1))
 		emu.writeLdrEntry(ldrEntry, "Load")
 		emu.writeLdrEntry(ldrEntry, "Memory")
diff --git a/windows/winemulator.go b/windows/winemulator.go
index 8eeb753..5194079 100644
--- a/windows/winemulator.go
+++ b/windows/winemulator.go
@@ -1,5 +1,6 @@
 package windows
 
+import "log"
 import "gopkg.in/yaml.v2"
 import "os"
 import "io/ioutil"
@@ -280,9 +281,14 @@ func New(path string, arch, mode int, args []string, verbose int, config string,
 	}
 
 	//load the PE
-	pe, _ := pefile.LoadPeFile(emu.Binary)
+	pe, err := pefile.LoadPeFile(emu.Binary)
+	if err != nil {
+		log.Println("unable to load PE file:", err)
+	}
 	err = emu.initPe(pe, path, arch, mode, args, calldllmain)
-
+	if err != nil {
+		log.Println("unable to load PE file:", err)
+	}
 	emu.Cpu = core.NewCpuManager(emu.Uc, emu.UcMode, emu.MemRegions.StackAddress, emu.MemRegions.StackSize, emu.MemRegions.HeapAddress, emu.MemRegions.HeapSize)
 	emu.Scheduler = NewScheduleManager(&emu)
 

from binee.

kgwinnup avatar kgwinnup commented on May 22, 2024 1

Yes, that is one of the values configurable with a yaml file, which can be provided via command line flags.

Other configurable options exist as well, the main struct definition is https://github.com/carbonblack/binee/blob/master/windows/winemulator.go#L24

from binee.

kgwinnup avatar kgwinnup commented on May 22, 2024 1

just pushed that "hotfix"

from binee.

kgwinnup avatar kgwinnup commented on May 22, 2024 1

thank you, saw all the PR's. This is great!

from binee.

kgwinnup avatar kgwinnup commented on May 22, 2024

Agree with you 100% on removing the apisetschema.dll requirement. Just a quick glance at the code and I don't believe it is a trivial change, but it is certainly possible. I think the challenge will just be going through the few places in the loader and a couple hooks and figure out a clean way of checking if the apiset exists or not. I believe there are a couple places where we (wrongly) assume values to be in the apiset object.

from binee.

mewmew avatar mewmew commented on May 22, 2024

While I have you on the phone, is emu.Opts.Root configurable? It seems like using temp works in most places for handling search paths for DLLs, but there are a few that are hard coded for emu.Opts.Root, e.g. from windows/ntdll.go:

data, err := ioutil.ReadFile(emu.Opts.Root + fmt.Sprintf("windows/system32/c_%d.nls", in.Args[1]))

The default value seem to be emu.Opts.Root = "os/win10_32/", so if not, I can just create a dummy os/win10_32 directory for now and symlink towards my real root.

from binee.

mewmew avatar mewmew commented on May 22, 2024

I tried the config file, but for some reason it doesn't seem to work. Using the dummy os/win10_32 symlink workaround worked however.

Contents of win.yaml :

$ cat win.yaml 
root: "/home/u/.wine/drive_c/"

Using win.yaml config:

$ binee -c win.yaml foo_32.exe
error finding file ntdll.dll
error finding file kernel32.dll
error finding file kernel32.dll
2019/11/21 21:56:35 unable to locate DLL "ntdll.dll"
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x28 pc=0x55b090]

goroutine 1 [running]:
github.com/carbonblack/binee/windows.(*WinEmulator).createLdrEntry(0xc000148900, 0x0, 0x1, 0x1)
	/home/u/Desktop/binee/windows/loader.go:291 +0x70
...

Using os/win10_32 symlink workaround:

$ mkdir os
$ ln -s /home/u/.wine/drive_c/ os/win10_32
$ binee foo_32.exe
panic: interface conversion: interface {} is *pefile.OptionalHeader32P, not *pefile.OptionalHeader32

goroutine 1 [running]:
github.com/carbonblack/binee/windows.(*WinEmulator).createLdrEntry(0xc000114900, 0xc000138100, 0x1, 0x9)
	/home/u/Desktop/binee/windows/loader.go:303 +0x3ec
...

Notice, the workaround gets further (crashes in a different place).

from binee.

kgwinnup avatar kgwinnup commented on May 22, 2024

ah, nice find. I think I found the bug, the search path never gets updated with the new Root if there is a config provided. https://github.com/carbonblack/binee/blob/master/windows/winemulator.go#L267

Does that sound like what your seeing? Just below that line, the config file is loaded and all the default values are overwritten with the configuration. However, the search path is never updated beyond line 267 it looks like.

from binee.

mewmew avatar mewmew commented on May 22, 2024

Hmm, from a quick glance at main.go, it seems like the config path of -c is never used (unless you also specify -a or -A).

	if options.ApisetDump {
		rootFolder := "os/win10_32/"
		if options.Config != "" {
			conf, err := util.ReadGenericConfig(options.Config)

...

	if options.ApisetLookup != "" {
		rootFolder := "os/win10_32/"
		if options.Config != "" {
			conf, err := util.ReadGenericConfig(options.Config)

edit: also, the way of handling command line arguments in binee looks very C-like. To clean up handling of command line arguments a bit, I'd suggest looking into using the flag package of the Go standard library.

from binee.

kgwinnup avatar kgwinnup commented on May 22, 2024

The config file is still used by Winemulator, however, with the call to New https://github.com/carbonblack/binee/blob/master/main.go#L192

At least in the early stage, this was originally poc'd in C. I'll look into flag though, thanks

from binee.

mewmew avatar mewmew commented on May 22, 2024

Ah, you are right.

Yes, so the issue you pointed out is indeed the cause. The search path should be set after reading the yml config.

-	emu.SearchPath = []string{"temp/", emu.Opts.Root + "windows/system32/", "c:\\Windows\\System32"}

 	var buf []byte
 	if buf, err = ioutil.ReadFile(config); err == nil {
 		_ = yaml.Unmarshal(buf, &emu.Opts)
 	}

+	emu.SearchPath = []string{"temp/", emu.Opts.Root + "windows/system32/", "c:\\Windows\\System32"}

from binee.

mewmew avatar mewmew commented on May 22, 2024

I'll look into flag, this was my first project in Golang, and it was (at least a very early stage of it) originally done in C.

No worries, I'm glad you decided to write it in Go, even if it started out as a learning experiment :) And things like these are easy to fix. As you go further, there will be more things you'll bump into and learn that would help make the code more idiomatic Go.

One such thing would be to group imports. An automatic way to do so is to run goimports.

-import "log"
-import "gopkg.in/yaml.v2"
-import "os"
-import "io/ioutil"
-import "time"
-import "github.com/carbonblack/binee/pefile"
-import "encoding/binary"
-
-//import "regexp"
-import cs "github.com/kgwinnup/gapstone"
-import uc "github.com/unicorn-engine/unicorn/bindings/go/unicorn"
-import "sort"
-import core "github.com/carbonblack/binee/core"

+import (
+	"encoding/binary"
+	"io/ioutil"
+	"log"
+	"os"
+	"sort"
+	"time"
+
+	"github.com/carbonblack/binee/core"
+	"github.com/carbonblack/binee/pefile"
+	cs "github.com/kgwinnup/gapstone"
+	uc "github.com/unicorn-engine/unicorn/bindings/go/unicorn"
+	"gopkg.in/yaml.v2"
+)

Note, in the above, I also removed the local package name core as binee/core was already called core, so no need for a rename.

To use goimports, do as follows.

go get golang.org/x/tools/cmd/goimports
goimports -w foo.go

I'll prepare a PR for you :)

from binee.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.