pe-util icon indicating copy to clipboard operation
pe-util copied to clipboard

Updated and expanded peldd for usage on Windows

Open roussosalex opened this issue 6 years ago • 26 comments

  • updated to newest pe-parse
  • added experimental filesystem support and c++17 filesystem support in addition to boost
  • tested on windows: compiles using mingw-w64, runs on windows
  • improved windows compatibility with additional options to include PATH and the cwd in the search path.
  • added some modern windows libraries to whitelist

roussosalex avatar May 09 '19 21:05 roussosalex

Is this package still maintained at all? ping @gsauthof

orgads avatar Jan 13 '22 15:01 orgads

Is this package still maintained at all? ping @gsauthof

Well, kind of. Although lately I don't have to target windows systems anymore. Thus, maintaining this project isn't my top priority.

However, please consider the following:

I prefer pull-requests that fix one thing and not bundle a bunch of issues together. Also, it's not sufficient to describe what is changed. It's more important to add why something is changed, i.e. adding some motivation.

For example, looking at this pull-request I really don't know why pe-utils was updated - is this update required to fix some issue? Why is experimental C++17 filesystem support added? etc.

Thus, this pull-request should be split into more digestible pieces.

gsauthof avatar Jan 24 '22 23:01 gsauthof

This pull request does fix one thing, which is compiling and using pe-utils on Windows. Maybe a more detailed explanation should have been given, but every commit in this PR also improves the compilation/usage of pe-util on Windows.

Because the project seemed inactive, some modernizations were added as well. Keeping all the changes in one place instead of splitting them across PRs allows others having the same issue to just use the PR branch.
  

Why is experimental C++17 filesystem support added

A central part of making pe-util easy to compile for/on Windows was getting rid of the boost dependency. Since mingw-w64 supports (experimental) C++17 filesystem, it was added as an option to avoid having to deal with boost on Windows. The Windows usage is also the motivation for expanding the whitelist, since Windows 10 introduces new system libraries and also why the search path and CWD options were added, since Windows searches these locations as well.   

Thus, this pull-request should be split into more digestible pieces.

I am not sure how to split it in a way that makes sense. If you like, I can try to split the modernization part from the Windows support.

roussosalex avatar Jan 25 '22 02:01 roussosalex

Resolved merge conflicts

roussosalex avatar Mar 03 '22 21:03 roussosalex

Good work, @roussosalex , I will try your branch today, thanks!

asmwarrior avatar Mar 04 '22 00:03 asmwarrior

I see this when I try to run cmake inside the msys2's mingw64.exe shell

zyh@WINMICR-0PLE9E2 MINGW64 /d/code/temp/pe-util/build
# cmake -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=Release ..
CMake Error at CMakeLists.txt:13 (else):
  Flow control statements are not properly nested.


-- Configuring incomplete, errors occurred!

Sorry, I don't know cmake very much.

asmwarrior avatar Mar 04 '22 00:03 asmwarrior

 CMakeLists.txt | 1 +
 1 file changed, 1 insertion(+)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2e43e20..6249991 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -16,6 +16,7 @@ else()
       set(Boost_ARCHITECTURE "-x64")
     else()
       set(Boost_ARCHITECTURE "-x32")
+    endif()
   endif()
     
   find_package(Boost 1.54 COMPONENTS

This is the fix.

asmwarrior avatar Mar 04 '22 00:03 asmwarrior

Fixed it. Thanks!

roussosalex avatar Mar 04 '22 00:03 roussosalex

I passed the cmake, but failed when running the mingw32-make.exe, see the log below:

zyh@WINMICR-0PLE9E2 MINGW64 /d/code/temp/pe-util/build
# cmake -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=Release -DUSE_FILESYSTEM=1 ..
-- VERSION file: D:/code/temp/pe-util/pe-parse/pe-parser-library/../VERSION
-- Configuring done
-- Generating done
-- Build files have been written to: D:/code/temp/pe-util/build

zyh@WINMICR-0PLE9E2 MINGW64 /d/code/temp/pe-util/build
# mingw32-make
[ 12%] Building CXX object CMakeFiles/peldd.dir/peldd.cc.obj
D:\code\temp\pe-util\peldd.cc:4:10: fatal error: parser-library/parse.h: No such file or directory
    4 | #include <parser-library/parse.h>
      |          ^~~~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
mingw32-make[2]: *** [CMakeFiles\peldd.dir\build.make:75: CMakeFiles/peldd.dir/peldd.cc.obj] Error 1
mingw32-make[1]: *** [CMakeFiles\Makefile2:99: CMakeFiles/peldd.dir/all] Error 2
mingw32-make: *** [Makefile:135: all] Error 2

asmwarrior avatar Mar 04 '22 01:03 asmwarrior

Looks like you may be using native mingw32-make in a unix-like MSYS2 shell. According to CMake documentation use the "MinGW Makefiles" generator only in a native shell like cmd.exe. For MSYS2 shell use "MSYS Makefiles" generator.

roussosalex avatar Mar 04 '22 01:03 roussosalex

NO, I think there are several kinds of shells.

When started by msys2.exe, it is a msys shell, but when started by mingw64.exe, it looks like a windows cmd.exe.

I just tried it in windows command line( I have put my F:\msys2\mingw64\bin in the PATH), it has the same error:

D:\code\temp\pe-util\build>cmake -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=Release -DUSE_FILESYSTEM=1 ..
-- The CXX compiler identification is GNU 11.2.0
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: F:/msys2/mingw64/bin/g++.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- The C compiler identification is GNU 11.2.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: F:/msys2/mingw64/bin/gcc.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- VERSION file: D:/code/temp/pe-util/pe-parse/pe-parser-library/../VERSION
-- Configuring done
-- Generating done
-- Build files have been written to: D:/code/temp/pe-util/build

D:\code\temp\pe-util\build>mingw32-make
[ 12%] Building CXX object CMakeFiles/peldd.dir/peldd.cc.obj
D:\code\temp\pe-util\peldd.cc:4:10: fatal error: parser-library/parse.h: No such file or directory
    4 | #include <parser-library/parse.h>
      |          ^~~~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
mingw32-make[2]: *** [CMakeFiles\peldd.dir\build.make:75: CMakeFiles/peldd.dir/peldd.cc.obj] Error 1
mingw32-make[1]: *** [CMakeFiles\Makefile2:99: CMakeFiles/peldd.dir/all] Error 2
mingw32-make: *** [Makefile:135: all] Error 2

D:\code\temp\pe-util\build>

asmwarrior avatar Mar 04 '22 01:03 asmwarrior

Do I have to build the parser-library first? I'm not good at cmake, but it looks like the git submodule is not build first.

asmwarrior avatar Mar 04 '22 01:03 asmwarrior

Looks like you updated the git submodule a little too much. Run git submodule update in pe-util and it should work again.

roussosalex avatar Mar 04 '22 01:03 roussosalex

OK, indeed, I have update the submodule too much(I mean I used the submodule's master head)

Now, the header issue is gone, but here comes another issue:

D:\code\temp\pe-util\build>cmake -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=Release -DUSE_FILESYSTEM=1 ..
-- The CXX compiler identification is GNU 11.2.0
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: F:/msys2/mingw64/bin/g++.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- The C compiler identification is GNU 11.2.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: F:/msys2/mingw64/bin/gcc.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: D:/code/temp/pe-util/build

D:\code\temp\pe-util\build>mingw32-make
[ 14%] Building CXX object pe-parse/pe-parser-library/CMakeFiles/pe-parser-library.dir/src/buffer.cpp.obj
[ 28%] Building CXX object pe-parse/pe-parser-library/CMakeFiles/pe-parser-library.dir/src/parse.cpp.obj
[ 42%] Linking CXX static library libpe-parser-library.a
[ 42%] Built target pe-parser-library
[ 57%] Building CXX object CMakeFiles/peldd.dir/peldd.cc.obj
D:\code\temp\pe-util\peldd.cc:26:23: error: 'filesystem' is not a namespace-name; did you mean 'system'?
   26 |   namespace fs = std::filesystem;
      |                       ^~~~~~~~~~
      |                       system
D:\code\temp\pe-util\peldd.cc: In function 'std::string peparse::_get_cwd()':
D:\code\temp\pe-util\peldd.cc:109:10: error: 'fs' has not been declared
  109 |   return fs::current_path().string();
      |          ^~
D:\code\temp\pe-util\peldd.cc: In function 'std::pair<std::deque<std::__cxx11::basic_string<char> >, bool> names(const char*)':
D:\code\temp\pe-util\peldd.cc:288:8: error: 'fs' has not been declared
  288 |   if (!fs::exists(filename))
      |        ^~
D:\code\temp\pe-util\peldd.cc: In member function 'std::string Path_Cache::resolve(const std::deque<std::__cxx11::basic_string<char> >&, const string&)':
D:\code\temp\pe-util\peldd.cc:470:9: error: 'fs' has not been declared
  470 |     if (fs::exists(path)) {
      |         ^~
D:\code\temp\pe-util\peldd.cc:475:26: error: 'fs' has not been declared
  475 |           for (auto &e : fs::directory_iterator(path)) {
      |                          ^~
D:\code\temp\pe-util\peldd.cc:480:31: error: 'fs' has not been declared
  480 |           return path + (char)fs::path::preferred_separator + resolve(r.first->second, filename);
      |                               ^~
D:\code\temp\pe-util\peldd.cc:482:31: error: 'fs' has not been declared
  482 |           return path + (char)fs::path::preferred_separator + resolve(i->second, filename);
      |                               ^~
D:\code\temp\pe-util\peldd.cc: In member function 'void Traverser::prepare_stack()':
D:\code\temp\pe-util\peldd.cc:518:24: error: 'fs' has not been declared
  518 |     auto p = make_pair(fs::path(a).filename().string(), a);
      |                        ^~
mingw32-make[2]: *** [CMakeFiles\peldd.dir\build.make:76: CMakeFiles/peldd.dir/peldd.cc.obj] Error 1
mingw32-make[1]: *** [CMakeFiles\Makefile2:99: CMakeFiles/peldd.dir/all] Error 2
mingw32-make: *** [Makefile:135: all] Error 2

D:\code\temp\pe-util\build>

asmwarrior avatar Mar 04 '22 01:03 asmwarrior

Yes your mingw compiler does not have C++17 filesystem, instead use USE_FILESYSTEM_EXPERIMENTAL=ON.

roussosalex avatar Mar 04 '22 01:03 roussosalex

I'm using the latest msys2 and its 64bit gcc 11 mingw compiler, not sure why it does not have C++17 I enable the -d option of mingw32-make.exe, and here is the log:

[ 57%] Building CXX object CMakeFiles/peldd.dir/peldd.cc.obj
Reaping winning child 000000000032d4c0 PID 3292816
CreateProcess(F:\msys2\mingw64\bin\g++.exe,F:\msys2\mingw64\bin\g++.exe -DUSE_FILESYSTEM @CMakeFiles/peldd.dir/includes_CXX.rsp -O3 -DNDEBUG -Wall -Werror -std=gnu++11 -MD -MT CMak
eFiles/peldd.dir/peldd.cc.obj -MF CMakeFiles\peldd.dir\peldd.cc.obj.d -o CMakeFiles\peldd.dir\peldd.cc.obj -c D:\code\temp\pe-util\peldd.cc,...)
Live child 000000000032d4c0 (CMakeFiles/peldd.dir/peldd.cc.obj) PID 3292816
D:\code\temp\pe-util\peldd.cc:26:23: error: 'filesystem' is not a namespace-name; did you mean 'system'?
   26 |   namespace fs = std::filesystem;
      |                       ^~~~~~~~~~
      |                       system
D:\code\temp\pe-util\peldd.cc: In function 'std::string peparse::_get_cwd()':
D:\code\temp\pe-util\peldd.cc:109:10: error: 'fs' has not been declared
  109 |   return fs::current_path().string();
      |          ^~
D:\code\temp\pe-util\peldd.cc: In function 'std::pair<std::deque<std::__cxx11::basic_string<char> >, bool> names(const char*)':
D:\code\temp\pe-util\peldd.cc:288:8: error: 'fs' has not been declared
  288 |   if (!fs::exists(filename))
      |        ^~

Strange, it still use gnu c++ 11.

But if I look at the CMakefiles, it has:

cmake_minimum_required(VERSION 3.0...3.22.1)
project(mingw_util CXX)

if (USE_FILESYSTEM)
  # available with gcc 8.0
  set(CMAKE_CXX_STANDARD 17)
  set(PE_COMPILE_DEF USE_FILESYSTEM)
  set(PE_LINK_DEF stdc++fs)
elseif(USE_FILESYSTEM_EXPERIMENTAL)
  # available with gcc 5.3
  set(PE_COMPILE_DEF USE_FILESYSTEM_EXPERIMENTAL)
  set(PE_LINK_DEF stdc++fs)

So, the question is: Why the C++ 17 is not enabled? My GCC certainly have such C++17 support, but the problem is the gnu++11 is passed in the command line.

asmwarrior avatar Mar 04 '22 02:03 asmwarrior

This is a known issue with mingw. Use experimental filesystem instead.

roussosalex avatar Mar 04 '22 02:03 roussosalex

This is a known issue with mingw. Use experimental filesystem instead.

Oh, I see that you have explicitly enabled C++11? Here is what I see in CMakefiles

set_target_properties(peldd PROPERTIES 
  CXX_STANDARD 11 
  CXX_STANDARD_REQUIRED ON
  )

asmwarrior avatar Mar 04 '22 02:03 asmwarrior

This is a known issue with mingw. Use experimental filesystem instead.

On, I see that you have expcitily enabled C++11? Here is what I see in CMakefiles

set_target_properties(peldd PROPERTIES 
  CXX_STANDARD 11 
  CXX_STANDARD_REQUIRED ON
  )

I just change this value from 11 to 17, and it builds OK now, see the log below:

D:\code\temp\pe-util\build>cmake -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=Release -DUSE_FILESYSTEM=ON ..
-- Configuring done
-- Generating done
-- Build files have been written to: D:/code/temp/pe-util/build

D:\code\temp\pe-util\build>mingw32-make
Consolidate compiler generated dependencies of target pe-parser-library
[ 42%] Built target pe-parser-library
Consolidate compiler generated dependencies of target peldd
[ 57%] Building CXX object CMakeFiles/peldd.dir/peldd.cc.obj
[ 71%] Building CXX object CMakeFiles/peldd.dir/pe-parse/pe-parser-library/src/parse.cpp.obj
[ 85%] Building CXX object CMakeFiles/peldd.dir/pe-parse/pe-parser-library/src/buffer.cpp.obj
[100%] Linking CXX executable peldd.exe
[100%] Built target peldd

asmwarrior avatar Mar 04 '22 02:03 asmwarrior

Here is the test result of the new built peldd.exe

F:\code\cb-64bit>peldd codeblocks.exe
SHFOLDER.dll
codeblocks.dll
exchndl.dll
libgcc_s_seh-1.dll
libstdc++-6.dll
wxmsw315u_gcc_cb.dll

F:\code\cb-64bit>peldd codeblocks.exe --all
Error: Could not resolve: SHFOLDER.dll

F:\code\cb-64bit>peldd codeblocks.dll
libgcc_s_seh-1.dll
libstdc++-6.dll
wxmsw315u_gcc_cb.dll

F:\code\cb-64bit>peldd codeblocks.dll --all
Error: Could not resolve: libgcc_s_seh-1.dll

F:\code\cb-64bit>

I'm not sure, but it looks like it can't do recursive resolve the dependency. I mean find the dependency of a dependency dll.

asmwarrior avatar Mar 04 '22 02:03 asmwarrior

You need to provide the correct search paths using the options -p, --search-env or --search-cwd.

roussosalex avatar Mar 04 '22 02:03 roussosalex

You need to provide the correct search paths using the options -p, --search-env or --search-cwd.

OK, let me check it.

BTW: I used another good tool to find the dependencies/even copy the dependencies, which is also cross platform, see here: brechtsanders/pedeps: Cross-platform C library to read data from PE/PE+ files (the format of Windows .exe and .dll files)

asmwarrior avatar Mar 04 '22 02:03 asmwarrior

I just tried, but still no luck:

F:\code\cb-64bit>peldd codeblocks.exe --search-env --all
Error: Could not resolve: wxmsw315u_gcc_cb.dll

In-fact, I can start the codeblocks.exe from the command line, and the wxmsw315u_gcc_cb.dll is the main dependency of the codeblocks, which is the wxWidgets library dll. I'm not sure it still can't resolve this dll.

asmwarrior avatar Mar 04 '22 02:03 asmwarrior

You probably need --search-cwd as well.

roussosalex avatar Mar 04 '22 02:03 roussosalex

You probably need --search-cwd as well.

Oh, this works, see the log below, thanks!!

F:\code\cb-64bit>peldd codeblocks.exe --search-env --all --search-cwd
C:\Windows\System32\KernelBase.dll
C:\Windows\System32\ntdll.dll
C:\Windows\System32\rpcrt4.dll
C:\Windows\System32\shfolder.dll
C:\Windows\System32\wsock32.dll
F:\code\cb-64bit\codeblocks.dll
F:\code\cb-64bit\exchndl.dll
F:\code\cb-64bit\mgwhelp.dll
F:\code\cb-64bit\wxmsw315u_gcc_cb.dll
F:\msys2\mingw64\bin\libgcc_s_seh-1.dll
F:\msys2\mingw64\bin\libstdc++-6.dll
F:\msys2\mingw64\bin\libwinpthread-1.dll
codeblocks.exe

asmwarrior avatar Mar 04 '22 02:03 asmwarrior

It looks like the search path parameter order matters, see this log:

F:\code\cb-64bit>peldd codeblocks.exe --search-cwd --all --search-env
C:\Windows\System32\KernelBase.dll
C:\Windows\System32\ntdll.dll
C:\Windows\System32\rpcrt4.dll
C:\Windows\System32\shfolder.dll
C:\Windows\System32\wsock32.dll
F:\code\cb-64bit\codeblocks.dll
F:\code\cb-64bit\exchndl.dll
F:\code\cb-64bit\libgcc_s_seh-1.dll
F:\code\cb-64bit\libstdc++-6.dll
F:\code\cb-64bit\libwinpthread-1.dll
F:\code\cb-64bit\mgwhelp.dll
F:\code\cb-64bit\wxmsw315u_gcc_cb.dll
codeblocks.exe

In this case, the dll in the same folder (cwd) is located first, which is the default way as the Windows OS.

asmwarrior avatar Mar 04 '22 05:03 asmwarrior