Comments (12)
@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.
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.
just pushed that "hotfix"
from binee.
thank you, saw all the PR's. This is great!
from binee.
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.
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.
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.
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.
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.
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.
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.
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)
- Bug in the windows loader when loading Aspack packed binaries HOT 1
- type assertion panic in `windows/loader.go`: interface conversion: interface {} is *pefile.OptionalHeader32P, not *pefile.OptionalHeader32
- unable to resolve indirect call; e.g. call eax, with eax = 0
- crashes with panic when running `binee doesnotexist.exe`
- debug output of first instruction of function missing when using `-v`
- inconsistent definition of nameToHook key in AddHook and ResolveNameToHook
- non-deterministic enumeration of imported libraries HOT 1
- incorrect execution of GetLastError, wrong set of assembly instructions executed HOT 11
- ntdll,user32: Add support for ntdll.KiFastSystemCall sysenter wrapper, as needed by NtUserCallOneParam and NtUserCallTwoParam of user32.dll HOT 1
- Report error to user if analysis is aborted prematurely
- Issues with mingw32-compiled PE32
- Incorrect return value of _p_fmode and _p_commode
- Question|Consult: Benignware Emulation of LOLBAS Interpreters HOT 1
- panic: runtime error: invalid memory address or nil pointer dereference HOT 7
- Add C++ Redistributable to Documentation/Wiki HOT 1
- Incorrect parsing of 64bit PE in readImports HOT 1
- Slack invite link in README is dead HOT 1
- Installation fails HOT 1
- Error finding dll files.
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from binee.