GrammaTech / ddisasm

A fast and accurate disassembler
https://grammatech.github.io/ddisasm/
GNU Affero General Public License v3.0
646 stars 60 forks source link

"Lib.exe: command not found" when reassembling PE binaries #56

Open mattr555-r opened 1 year ago

mattr555-r commented 1 year ago

(Ran on Ubuntu 18.04, and also ran the test on Windows 11)

After running any PE binary (32 or 64 bit) through ddisasm, and getting the resulting .gtirb, I go to use gtirb-pprinter to reassemble the .exe but always get the same error: "lib.exe: command not found". Additionally I also get "ml64.exe: command not found". Is this a related issue?

How do I fix this?

aeflores commented 1 year ago

Hi @mattr555-r, gtirb-pprinter generates new binaries by generating an assembly file and then calling an off-the-self assembler and linker to produce a new binary.

Both ml64.exe and lib.exe are part of MS Visual Studio, so if you want to reassemble a PE file you need Visual Studio installed and in your path so gtirb-pprinter can find it. This should be easy to do in Windows.

It usually amounts to running the corresponding .bat file (see https://learn.microsoft.com/en-us/cpp/build/building-on-the-command-line?view=msvc-170#developer_command_file_locations). For 64 bit it's vcvars64.bat.

In linux there are a couple of options you can try:

Option 1: Use wine

We often use https://github.com/mstorsjo/msvc-wine as follows:

Build a docker image

git clone https://github.com/mstorsjo/msvc-wine
cd msvc-wine
docker build -t msvc-wine  .

Create scripts to redirect lib.exe and ml64.exe calls:

Create a script called lib.exe that contains:

#!/bin/bash
docker run -it --rm -v /tmp:/tmp -v $PWD:/data -w /data --entrypoint /opt/msvc/bin/x64/lib.exe msvc-wine $@

and a ml64.exe script that contains:

#!/bin/bash
docker run -it --rm -v /tmp:/tmp -v $PWD:/data -w /data --entrypoint /opt/msvc/bin/x64/ml64.exe msvc-wine $@

Then, you can do:

PATH=$PATH:$PWD gtirb-pprinter ex.gtirb -b ex_rewritten.exe

Option2: use uasm+mingw+llvmdlltool

You can use uasm to reassemble programs into object files (see https://git.grammatech.com/rewriting/ddisasm/-/blob/main/.ci/Dockerfile.ubuntu20#L86 for how to build it) and use mingw for linking (use package https://git.grammatech.com/rewriting/ddisasm/-/blob/main/.ci/Dockerfile.ubuntu20#L141).

You can run the pprinter as follows:

gtirb-pprinter ex.gtirb --asm ex.asm --syntax uasm -b ex_rewritten.exe

This will fail to generate a binary, but it will generate an assembly file ex.asm and it will call llvm-dlltool to generate lib files from .def files. E.g. you should see something like this as part of the output:

lib.exe: command not found
Execute: llvm-dlltool -d /tmp/filepdUZl8.def -l KERNEL32.lib -m i386:x86-64

Then you can use uasm to generate a new object file:

uasm -win64 -nologo -Fo ex.o ex.asm

And use mingw for linking:

x86_64-w64-mingw32-ld ex.o -o ex_rewritten.exe KERNEL32.lib --entry __EntryPoint --subsystem console

The arguments to the linker will vary depending on your program, but you can see the (failed) call to ml64 in the pprinter output and use that as a starting point. E.g. all lib files generated with llvm-dlltool should be passed to mingw.

Hopefully this helps!