Open qknight opened 5 months ago
And .bss section looks like this from the PE header:
What's the reason you showed this? It seems fine to me. sizeOfRawData
is always 0 for .bss
.
section name: /4, raw_data_size: 22800 !virtual_address !pointer_to_raw_data
The first problem here is that this is using long section names, which requires writing the symbol table and string table, but pe::Writer
doesn't support that.
For the assertions, I'm not 100% sure because I don't have your binary to look at, but for the binary I tested on here, the problem is that the .reloc
section occurs in between this section and the previous one, but pecopy
skips over .reloc
, which messes up the address and file offsets.
You could maybe fix that with a patch like this:
--- a/crates/examples/src/bin/pecopy.rs
+++ b/crates/examples/src/bin/pecopy.rs
@@ -114,6 +114,11 @@ fn copy_file<Pe: ImageNtHeaders>(in_data: &[u8]) -> Result<Vec<u8>, Box<dyn Erro
let mut in_sections_data = Vec::new();
for index in &in_sections_index {
let in_section = in_sections.section(*index)?;
+ let offset = in_section.pointer_to_raw_data.get(LE);
+ if offset != 0 {
+ writer.reserve_until(offset);
+ }
+ writer.reserve_virtual_until(in_section.virtual_address.get(LE));
let range = writer.reserve_section(
in_section.name,
in_section.characteristics.get(LE),
but that still doesn't produce a working executable, and I haven't debugged further to find out why.
So, the pecopy
example is not a useful tool. It exists only as an example of how to use the API for write::pe::Writer
, and to show that it is capable of writing a valid executable. It copies another file simply because that is the easiest way to provide data for it to write, but it shouldn't be expected that is it capable of copying any file.
If we were to provide support for being able to copy any file, what needs to be done is to add build::pe::Builder
, similar to the existing ELF builder. I made a start on this a while ago, but didn't get far yet. I don't know when I'll get back to it.
In the meantime, you may want to look at using goblin
. I know that someone else has done work there in this area, see https://github.com/m4b/goblin/pull/389 and https://github.com/RaitoBezarius/ifrit.
I've added .xdata
and .bss
as I originally thought to be wrong and the screenshot might help you.
The main.exe in question can be found at https://nixcloud.io/mini-main.zip and it also contains the source code. It creates some files in your windows temp for testing std::filesystem on windows with symlinks. It requires c:\nix to exist. Don't run it but if you do it probably won't damage anything. This is how I compile it: https://lastlog.de/blog/libnix_mingw_status.html and I provide this since you might be curious what I'm doing.
Can you please explain why pecopy
is not useful? It seems to do exactly what I want from it: parse a PE header, relocate symbols and write it back. The only thing I want to add is parsing & rewriting the .idata
section because this contains the dll names I want to change.
I'll need to have a closer look into the goblin link you provided, thanks!
[nixos@nixos:~/nix/t]$ ./main.exe
0
0
1
0
"c:" -> dir is not an absolute path
not an absolute path
"c:"
"c:\\" -> "c:\\"
"c:\\nix\\..\\nix" -> "c:\\nix"
da test -> c:\nix-hack\foo
c:\nix
c:\nix\asdf\
\\wsl.localhost\nixos\home\nixos\nix\t
creating tmp path: C:\Users\joschie\AppData\Local\Temp\
Error creating file symlink
A required privilege is not held by the client
Error creating directory symlink
A required privilege is not held by the client
Error creating directory symlink
A required privilege is not held by the client
Error creating directory symlink
A required privilege is not held by the client
c:\nix\lnks -> "c:\\nix\\lnks"
For me, using your patch and reenabling assertions, it produces a working executable!
.\main-pecopy.exe
0
0
1
0
"c:" -> not an absolute path
"c:"
"c:\\" -> "c:\\"
"c:\\nix\\..\\nix" -> "c:\\nix"
da test -> c:\nix-hack\foo
c:\nix
c:\nix\asdf\
C:\nix-hack
creating tmp path: C:\Users\joschie\AppData\Local\Temp\
Error creating file symlink
A required privilege is not held by the client
Error creating directory symlink
A required privilege is not held by the client
Error creating directory symlink
A required privilege is not held by the client
Error creating directory symlink
A required privilege is not held by the client
c:\nix\lnks -> "c:\\nix\\lnks"
Can you please explain why pecopy is not useful? It seems to do exactly what I want from it: parse a PE header, relocate symbols and write it back. The only thing I want to add is parsing & rewriting the .idata section because this contains the dll names I want to change.
It's not useful as is because it doesn't do any modifications to the data, and it doesn't claim to support everything possible in a PE file. However, if you can get it to work for what you need then that's great.
The mini-main.zip doesn't appear to be the same file that you were using in your initial report, because it doesn't contain any sections with long names, and pecopy works on it without the need for any patch.
I think I uploaded the original binary to https://nixcloud.io/nix.exe but know it is rather big.
Thanks for your explanation. PE modifications are indeed very hard as there are so many compiler/linker specific details which are easy to miss when doing rewrites.
I looked at the ifrit link you pointed me to, looks promising but bails out for main.exe and nix.exe with:
.\pe_add_section.exe c:\nix-hack\nix.exe out.exe
...
thread 'main' panicked at examples\pe_add_section.rs:33:44:
called `Result::unwrap()` on an `Err` value: Malformed("DOS header is malformed (signature 0x0)")
I'll have to re-consider possible solutions to my dll name patching with this knowledge.
Seems it does not like mingw/ld binaries.
I've tried to use pecopy (commit aa2f5adc8badeac3dadaf26e9dacb66784d5d643) on Windows using:
This works nicely!
But using it on nix.exe, which i built using mingw from linux in a cross compiler setup, it hits all 3 assertions:
I removed the asserts and added the !virtual_address and !pointer_to_raw_data print instead, this is what it looks like for the segments:
This is the output of the relevant data points:
And .bss section looks like this from the PE header:
Ideas how this could be fixed?