2

I will explain the code briefly. I want to add the contents of some .dlls in a specific binary (exe). When I need it, I will remove the dlls from within this binary. This process will perform better in the CI / CD processes. The following code works perfectly for a 32-bit python interpreter and a 32-bit binary.

Issue Report: I can't do this process for 64-bit binaries even with the 64-bit interpreter. With the 64-bit interpreter I cannot load 32-bit or 64-bit binaries. The question is whether there is a way or perhaps a library like win32api, like a "win64api"?

The result for the attempt is always:

pywintypes.error: (193, 'LoadLibrary', '% 1 is not a valid Win32 application.')

My question: Is there any form / module / library that can perform this task on 64-bit files?

Environment and sample binaries:

Works perfectly:

Doesn't work:

Local specs

  • platform.platform() >> 'Windows-10-10.0.18362-SP0'

  • platform.uname() >> uname_result(system='Windows', node='DESKTOP-SER206K', release='10', version='10.0.18362', machine='AMD64', processor='AMD64 Family 21 Model 2 Stepping 0, AuthenticAMD')

Sample code

import os
import win32api
import win32con
import base64

binary = "C:\\Users\\Guto\\Documents\\python\\python-3.7.7.exe"
assert os.path.exists(binary)
PATH_RC = "C:\\Users\\Guto\\Documents\\python\\sqlite3.dll"
assert os.path.exists(PATH_RC)

# Get a handle that can be used by the UpdateResource()
h = win32api.BeginUpdateResource(binary, 0)
rc_content = open(PATH_RC, "rb").read()
rc_content_b64 = base64.b64encode(rc_content)
win32api.UpdateResource(h, win32con.RT_STRING, "rc_content_b64", rc_content_b64)
# End the update resource of the handle.
win32api.EndUpdateResource(h, 0)

#at this point, I have a modified binary
#then I will access that information

h = win32api.LoadLibrary(binary)
r_list = win32api.EnumResourceNames(h, win32con.RT_STRING)
#Find and Load a resource component
resource = win32api.LoadResource(h, win32con.RT_STRING, "rc_content_b64")

new_rc_content = base64.b64decode(resource)
#Write the DLL again
NEW_PATH_RC = "C:\\Users\\Guto\\Documents\\python\\new_dll.dll"
with open(NEW_PATH_RC, "wb") as f:
    f.write(new_rc_content)
Guto G
  • 21
  • 1
  • 5
  • @IInspectable thx, i updated the issue report! – Guto G Jun 12 '20 at 21:08
  • https://stackoverflow.com/questions/57187566/python-ctypes-loading-dll-throws-oserror-winerror-193-1-is-not-a-valid-win/57297745#57297745. Also: https://github.com/CristiFati/Prebuilt-Binaries/tree/master/SQLite/v3.31.1. – CristiFati Jun 12 '20 at 21:37
  • I'm still not sure I fully understand, what you are trying to accomplish. As I read it, you have a binary (.exe) file and wish to embed a library (.dll) as a binary resource into it, which will ultimately get unpacked at a later stage. Is that correct? – IInspectable Jun 13 '20 at 11:07
  • @IInspectable Yes, exactly that! – Guto G Jun 14 '20 at 04:02
  • I'm guessing the embedding part works as expected. Well, sort of. `RT_STRING` is limited to 65535 bytes of data. You should really be using [RT_RCDATA](https://docs.microsoft.com/en-us/windows/win32/menurc/resource-types) and just dump the raw binary data (without base64 encoding it). What's failing is the unpacking, due to the call to `LoadLibrary`. Replace that with `LoadLibraryEx` and use the `LOAD_LIBRARY_AS_DATAFILE` and `LOAD_LIBRARY_AS_IMAGE_RESOURCE` flags. At that point you can access the resources irrespective of the bitness of the calling process and binary modules involved. – IInspectable Jun 14 '20 at 06:32
  • @IInspectable why didn't you write that as an answer? – Mark Ransom Jun 15 '20 at 16:08
  • @IInspectable Please, write as an answer, so I can select as correct. Thank you very much. – Guto G Jun 15 '20 at 16:26
  • 1
    @mar I'm not familiar with Python. If you are, feel free to transliterate my comment into an answer. – IInspectable Jun 15 '20 at 16:33

1 Answers1

2

64 bit processes simply cannot load 32-bit DLLs, it simply will not work. 64-bit windows can, of course, still run 32-bit executables and those can load 32-bit DLL files.

SoronelHaetir
  • 14,104
  • 1
  • 12
  • 23
  • Unless you are mistaken, it was not possible to load 32x or 64x binaries using a python 64 interpreter. I believe that win32api (as the name suggests) works for 32 bits only. The question is whether there is a way to use this in 64 bits? btw: The result for a 32 or 64 binary from the 64 interpreter is always this: pywintypes.error: (193, 'LoadLibrary', '%1 is not a valid Win32 application.') – Guto G Jun 12 '20 at 21:06
  • @GutoG "win32" is the name of the generic Windows API, whether you're calling it from a 32-bit or 64-bit program. Perhaps it was a mistake on Microsoft's part to put 32 in the name, but they were trying to differentiate it from the 16-bit API that came before it. This answer is correct, you can't mix 32 and 64 bit code in the same task space - the error message may be a bit misleading. – Mark Ransom Jun 12 '20 at 21:23
  • @Mark Ransom I understood, but I was not able to load a 32-bit binary, with a python x64 interpreter! Anyway thx very much to everyone. – Guto G Jun 12 '20 at 21:42
  • This isn't strictly correct. A process of any bitness can load a binary of any bitness, so long as it does not get the OS loader involved to prepare execution. [LoadLibraryEx](https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw) can load a binary as a datafile. Which is, presumably, what the OP is trying to do to embed a binary into an executable image's resource section. – IInspectable Jun 12 '20 at 21:57