Lift x64 Windows executable to LLVM bitcode and then compile back to x32 one? - windows

So my idea is to "lift" 64-bits Windows executable to LLVM bitcode (or whatever is higher than assembly) and then compile it back to 32-bit executable.
I found that RetDec and McSema can lift PE binary to LLVM IR (and optionally C), but McSema requires IDA pro so I haven't tried it yet.
I have installed MSVC v143 and Windows SDK version 10.0.19041.0:
Clang version:
clang version 13.0.1 (https://github.com/llvm/llvm-project 75e33f71c2dae584b13a7d1186ae0a038ba98838)
Target: x86_64-pc-windows-msvc
Thread model: posix
So I compile this Hello World code in C using Clang:
#include <stdio.h>
int main()
{
printf("Hello, world!\n");
}
then clang hello.c -o hello.exe
Check hello.exe file type with WSL:
$ file hello.exe
hello.exe: PE32+ executable (console) x86-64, for MS Windows
You can download it here.
Then I use RetDec to lift it to LLVM IR:
python retdec-decompiler.py --no-memory-limit hello.exe
Output: here
After that we get:
Compile bitcode back to executable:
clang hello.exe.bc -m32 -v -Wl,/SUBSYSTEM:CONSOLE -Wl,/errorlimit:0 -fuse-ld=lld -o hello.x86.exe
Output: here
I guess functions like _WriteConsoleW are Win32 APIs, but ___decompiler_undefined_function_0 might be generated from the decompiler by some way.
Also, the decompiled code has no main function, but it had entry_point function. From hello.exe.ll:
hello.exe.c also has entry_point instead of main:
And also, hello.exe.c doesn't have ___decompiler_undefined_function_0
I also tried running the bitcode with lli:
lli --entry-function=entry_point hello.exe.bc
Output: here
Here is the link to the files.
How to make this compile? Thanks!

That's very ambitious.
I'm going to go out on a limb and say that every windows application includes thousands of system header files, most of which use types whose size differs between 32- and 64-bit systems and many of which contains #ifdef or other platform-dependent differences. You'll have a large .ll file full of windows64-specific types and code.
If the developers at Microsoft saw windows64 as a good chance to drop some hacks that were needed for w95 code, then you'll have w32-incompatible code there, too.
What you have to do is what the wine developers did — add code to cater to each problem in turn. There will be thousands of cases to handle. Some of it will be very difficult. When you see the number 128 in the .ll file, was it sizeof(this_w64_struct) in the original source, sizeof(that_other_struct) or something else entirely? Should you change the number, and if so, to what?
You should expect this project to take at least years, maybe a decade or more. Good luck.

Related

How can I make GCC generate ELF object files?

I need to use the TCC compiler to link object files generated by GCC. However, GCC in MinGW outputs object files in COFF format, and TCC only supports the ELF format. How can I make GCC generate ELF object files?
$ cat test.c
int main(void)
{
return 0;
}
$ gcc -c test.c
$ file test.o
test.o: MS Windows COFF Intel 80386 object file
$ tcc -c test.c
$ file test.o
test.o: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped
However, GCC in MinGW outputs object files in COFF format
GCC can be configured to generate various outputs (including ELF) regardless of which host it runs on.
That is, a GCC running on Linux could be configured to generate COFF, and a GCC running on Windows could be configured to generate ELF32 or ELF64, for various processors (e.g. x86, or SPARC, or MIPS).
A compiler that runs on one kind of host, but generates code for a different kind, is called a cross-compiler.
TCC only supports the ELF format
This is not a meaningful statement: it could mean that you want GCC to generate ELF32 for i686 Linux, or ELF64 for SPARC Solaris, or any number of other processor/os/bit combinations.
You should figure out what target processor and operating system you want to run your final executable on, and then build (non-trivial) or download appropriate cross-compiler from Windows to that target.
file test.o
test.o: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped
Ok, you want Windows to Linux/i386/ELF32 cross-compiler.
strip might help. strip accepts various object file formats for input and output type (the bfdname). strip --info for the supported formats.
strip -o outputname -O elf32-i386 objfile Doing so on a 64 bit executable, converted to 32bit control headers will lead to nothing but crash, so pick your output form carefully. Make sure you aren't changing assumed bitwidths / endians along with headers.
Not running MinGW, so, not tested, may not work for your needs, or worse, may jump and catch fire.
You want your compiler (MinGW) to generate binaries that are not of the type usable for your host system (Windows). This is called cross-compiling, and it is a somewhat involved subject -- because to create complete executables you will also need the various libraries: standard libraries, target OS libraries, third-party libraries... so it is not merely the subject of "how do I get the compiler to create ELF", but also "how do I get the whole supporting cast of ELF libs so I can link against them?".
OSDev has quite extensive documentation on the subject of setting up a cross-compiler; however, since you did not tell us what exactly your problem is, it is difficult to advise you further.
If what you want is generating Linux binaries, my advise would be to not bother with cross-compilation (which is a tricky subject -- and much better supported the other way around, i.e. targeting Windows from Linux), but rather install a Linux distribution in parallel to your Windows, and work natively with that.

Cross-compiling baremetal Rust for Raspberry Pi 3 B from Windows

I'm trying to follow this blog but on Windows and with the latest Rust. It seems to me that the correct way of doing things like this is changing very frequently with Rust, so I'm hoping for an up-to-date Windows adaptation.
What I've tried so far:
I installed gcc-arm-embedded.
I had unverified partial success manually cross-compiling libcore, but then I switched to use the recommended xargo, the functionality of which (I read) is on its way to being included in Cargo eventually. While I don't understand any of it very well, I'm hoping to get to the part where I can write/run the code and then maybe I can back into understanding the compilation better.
With japaric's awesome help, I was able to get the "aarch64" targeted build working to generate the .o file (as of this particular commit).
And this part seems to verify:
$ file target/aarch64-raspi3-none-elf/release/deps/rust_rasp-ed0c2377e0a7df81.o
target/aarch64-raspi3-none-elf/release/deps/rust_rasp-ed0c2377e0a7df81.o: ELF 64-bit LSB relocatable, ARM aarch64, version 1 (SYSV), not stripped
When I try to use the GNU Arm Embedded Toolchain linker, I get:
$ arm-none-eabi-gcc -O0 -mfpu=vfp -mfloat-abi=hard -march=armv6zk -mtune=arm1176jzf-s -nostartfiles target/aarch64-raspi3-none-elf/release/deps/rust_rasp-ed0c2377e0a7df81.o -o kernel.elf target/aarch64-raspi3-none-elf/release/deps/rust_rasp-ed0c2377e0a7df81.o: file not recognized: File format not recognized
collect2.exe: error: ld returned 1 exit status
And #rust IRC chatroom helpfuls told me that rpi3 is aarch64, not arm, so I need to find an aarch64 linker ...
I think it's working! Things I learned:
xargo is good
rpi3 is different enough from rpi2 to cause my problems in tool selection
xargo doesn't care what toolchain rustup defaults to because I'm not asking it to link for me and it does its own toolchain selection
I needed to target aarch64, not arm. For this I used the linaro aarch64 mingw32 download, unpacked, added its bin folder to my PATH. Then the aarch64 tools were easy to adapt from the blog.
For people who want to do this themselves, see https://github.com/JasonKleban/rust-rasp . Not so complicated!
I aim to blink the onboard activity led as confirmation that we do really have control, but looks like that will be kinda complicated on the rpi3 (see my readme, if still applicable)

What do you need to install to use Clang on windows to build c++14 for 64 bit?

UPDATE:
I've written a detailed tutorial that incorporates the top two answers on this question: http://blog.johannesmp.com/2015/09/01/installing-clang-on-windows-pt1/
TL;DR
On Windows, Given the following program:
#include <iostream>
int main()
{
int arr[] = {1, 2, 3, 4, 5};
for(auto el : arr)
{
std::cout << el << std::endl;
}
return 0;
}
I want to be able to do the following:
clang++ hello.cpp -o hello.exe -std=c++14
And get a 64 bit executable that just works. I don't want to have to append a ton of -I includes to tell clang where to find iostream or other standard c++ headers; I don't want to have to link in multiple steps.
I don't care so much about performance, efficiency, what linker is used, etc. I just want to be able to have clang/gcc/whatever set up correctly so that I can use a single, quick and dirty, console command like the one above.
What do I need to install for that to just work?
The Problem
As a predominately mac/linux user I'm used to being able to just use a package manager to install the latest version of clang, which just works.
I'm now trying to set up clang/gnu compiler on windows and it seems to be far more difficult, If only because there is little to no straightforward documentation out there (that I've been able to find)
I've tried to follow this tutorial: https://yongweiwu.wordpress.com/2014/12/24/installing-clang-3-5-for-windows - and was able to use it to get clang to build and link (using gcc 4.8.2), but the resulting binaries were 32 bit.
I've tried installing the latest prebuilt binaries of clang (3.6.2) and the 64 bit version of mingw-w64 (4.9.3 for 64 bit with posix and sjlj for exceptions), and am getting:
hello.cpp:1:10: fatal error: 'iostream' file not found
#include <iostream>
^
1 error generated.
Which seems to indicate that clang is not seeing gcc's files. It seems that some versions of LLVM/clang are looking for only certain versions of gcc, but that doesn't seem to be documented anywhere?
Similarly someone mentioned to me on the LLVM IRC that you need to modify clang's driver to look for gcc in certain paths?
What I'm looking for
I'm fine with building LLVM/Clang from source if necessary, but I'm really just looking for clear, step-by-step instructions that allow me to use clang++ as easily as I'm able to do with mac/linux
Something like:
Build this version of LLVM/Clang and place it in that directory
Download and install this version of cygwin (or mingw32 or mingw-w64) and install these packages.
etc..
Try installing MSYS2 and then installing the mingw-w64-x86_64-clang (binary) package:
pacman -S mingw-w64-x86_64-clang
It is a bit old at the moment (3.6.2), but it might be good enough for you. Then when you run the Win64 shell provided by MSYS2, clang will be on your path.
If it's not good enough, I have recently been building a 64-bit version of clang with MSYS2 and using it to compile native 64-bit Windows executables. My process was something like:
Use pacman to install base-devel, mingw-w64-x86_64-ninja, mingw-x86_64-cmake and perhaps some other packages that are needed by the build process.
Grab my PKGBUILD script for clang and the files in the same directory. This is based on the mingw-w64-clang-svn package from MSYS2, which is largely the work of Martell Malone. You can find him on the MSYS2 IRC channel and ask him more about it.
In a Win64, shell, go to the directory with my PKGDUILD, run export MINGW_INSTALLS=mingw64 (so you are only compiling the 64-bit version), and then run makepkg-mingw.
It is unlikely you will get everything right on the first try, and some files might need to be edited. Clang may have changed since the last time I did this and some patches might not apply cleanly.
if you use the upcoming clang 3.7.0, simply set PATH to include mingw-w64's bin, clang will work as you expect
You can install llvm pre-release binary for Windows here. MinGW-w64 can be downloaded here. Of course, you should make sure the paths are properly set up.
For the latest version of clang, e.g., clang 6.0.0. The above solution by #user5271266 will not be enough. Now the default target for clang Windows is x86_64-pc-windows-msvc (Assume that you are using 64 bit Windows).
In order to compile C++ source files, according to here, we should change the target:
clang++ -target x86_64-pc-windows-gnu -std=c++14 test.cc -o test.exe

Cross compilation: GCC ignores --sysroot

I'm trying to cross compile programs (currently avconv from libav) for a Nokia N9 phone using arm-linux-gnueabi-gcc from Linux Mint's 64-bit repository. The compiler's libc version is 2.15 and the phone has libc-2.10.1. They have an incompatibility in the math library, which gives me a segfault when I compile and run the avconv program from libav.
I'd need to compile and link against the older libc version, but I haven't managed to get the --sysroot option to work.
I made a small test program to avoid repeatedly configuring and compiling libav.
arm-linux-gnueabi-gcc --sysroot=/opt/CrossCompilation/NokiaN9/ -o output.sysroot hello.c
arm-linux-gnueabi-gcc -o output.nosysroot hello.c
Both commands create an identical output file. This is what hello.c looks like:
#include <stdio.h>
#include <math.h>
int main() {
printf("Hello, World! Sin = %f\n", sin(0.6451));
}
The strangest part is that gcc completely ignores the --sysroot option. If I pass a nonexisting directory to sysroot, it still produces exactly the same output binary:
arm-linux-gnueabi-gcc --sysroot=/foo/bar -o output.foobar hello.c
It doesn't even complain about any errors. What's the problem?
since I wasted a few days messing with this before reading the comments, I'm going to post artless noise's comments as an answer:
"Run the compiler with arm-linux-gnueabi-gcc -v and look at the value of --with-sysroot; this is the directory the compiler was built with. If you have this directory present on your machine (maybe with a different compiler), then the --sysroot may not work[; and if you do not see --with-sysroot and instead see --with-libs, it] means your gcc is compiled without --sysroot support."

bash: ./mips-linux-gnu-gcc: cannot execute binary file error

I've recently installed a mips-linux-gnu-gcc crosstool in my linux machine which is based on i686. When I want to compile some codes, it showed me that error.
Every installing step was followed by http://developer.mips.com/tools/compilers/open-source-toolchain-linux/
After I installed the crosstool, I wrote a simple helloworld C file like this:
#include<stdio.h>
int main(void)
{
printf("Hello World!\n");
return 0;
}
But when I run:
/mips-linux-gnu-gcc hello.c -o hello -static
The compiler just print error:
bash: ./mips-linux-gnu-gcc: cannot execute binary file
I'm wondering maybe I've made some mistakes in some steps, but I can't figure it out.
Maybe some of you can help me, I'm confused by the problem.
The compiler you downloaded from MIPS is a 64-bit executable. Are you running a 32-bit host?
If you need a cross compiler for a 32-bit host targeting MIPS GNU/Linux, consider using the Sourcery CodeBench Lite compiler for MIPS GNU/Linux targets:
Sourcery CodeBench Lite for MIPS GNU/Linux
The link to the Sourcery CodeBench tools above comes from the MIPS pages just one level up from the link you provided:
MIPS Compilers Page
It looks like the mips-linux-gnu-gcc binary does not match the architecture of the machine you are trying to run it on. This might be something like a 32/64 bit mismatch.
Try using the free Mentor/Codesourcery MIPS gnu/gcc cross compilation tool chain instead. You can download from here.

Resources