Porting Windows Dynamic Link Libraries to Linux
Introduction
This repository contains a library that allows native Linux programs to load
and call functions from a Windows DLL.
As a demonstration, I’ve ported Windows Defender to Linux.
$ ./mpclient eicar.com
main(): Scanning eicar.com...
EngineScanCallback(): Scanning input
EngineScanCallback(): Threat Virus:DOS/EICAR_Test_File identified.
How does it work?
The peloader
directory contains a custom PE/COFF loader derived from
ndiswrapper. The library will process the relocations and imports, then provide
a dlopen
-like API. The code supports debugging with gdb (including symbols),
basic block coverage collection, and runtime hooking and patching.
What works?
The intention is to allow scalable and efficient fuzzing of self-contained
Windows libraries on Linux. Good candidates might be video codecs,
decompression libraries, virus scanners, image decoders, and so on.
- C++ exception dispatch and unwinding.
- Loading additional symbols from IDA.
- Debugging with gdb (including symbols), breakpoints, stack traces, etc.
- Runtime hooking and patching.
- Support for ASAN and Valgrind to detect subtle memory corruption bugs.
If you need to add support for any external imports, writing stubs is usually
quick and easy.
Why?
Distributed, scalable fuzzing on Windows can be challenging and inefficient.
This is especially true for endpoint security products, which use complex
interconnected components that span across kernel and user space. This
often requires spinning up an entire virtualized Windows environment to fuzz
them or collect coverage data.
This is less of a problem on Linux, and I’ve found that porting components of
Windows Antivirus products to Linux is often possible. This allows me to run
the code I’m testing in minimal containers with very little overhead, and
easily scale up testing.
This is just personal opinion, but I also think Linux has better tools. ¯\_(ツ)_/¯
Windows Defender
MsMpEng is the Malware Protection service that is enabled by default on Windows
8, 8.1, 10, Windows Server 2016, and so on. Additionally, Microsoft Security
Essentials, System Centre Endpoint Protection and various other Microsoft
security products share the same core engine.
The core component of MsMpEng responsible for scanning and analysis is called
mpengine. Mpengine is a vast and complex attack surface, comprising of handlers
for dozens of esoteric archive formats, executable packers, full system
emulators for various architectures and interpreters for various languages. All
of this code is accessible to remote attackers.
Building
To build the test client, simply type make
.
Dependencies
Note that the .i686
or :i386
suffixes are important, we need the 32bit libraries to use the 32bit dll.
Fedora / RedHat | Ubuntu / Debian | Comment |
---|---|---|
glibc-devel.i686 |
libc6-dev:i386 / libc6-dev-i386 |
Name varies with version. |
libgcc.i686 |
gcc-multilib |
|
readline-devel.i686 |
libreadline-dev:i386 |
Optional, used in mpscript. |
cabextract |
cabextract |
Used to extract definitions. |
You will need to download the 32-bit antimalware update file from this page:
- https://www.microsoft.com/security/portal/definitions/adl.aspx#manual
This should be a direct link to the right file:
- https://go.microsoft.com/fwlink/?LinkID=121721&arch=x86
This will download a file called mpam-fe.exe
, which is a cabinet file that
can be extracted with cabextract
. Extract the files into the engine
directory:
$ cabextract mpam-fe.exe
Extracting cabinet: mpam-fe.exe
extracting MPSigStub.exe
extracting mpavdlta.vdm
extracting mpasdlta.vdm
extracting mpavbase.vdm
extracting mpasbase.vdm
extracting mpengine.dll
All done, no errors.
If you want to know which version you got, try this:
$ exiftool mpengine.dll | grep 'Product Version Number'
Product Version Number : 1.1.13701.0
Running
The main mpengine loader is called mpclient
, it accepts filenames to scan as
a parameter.
$ ./mpclient netsky.exe
main(): Scanning netsky.exe...
EngineScanCallback(): Scanning input
EngineScanCallback(): Threat Worm:Win32/Netsky.P@mm identified.
There are some other sample tools, mpstreamfuzz
and mpscript
.
Debugging
If you want to debug a crash, single step through a routine or set breakpoints,
follow these examples. First, you need a map file from IDA.
Microsoft doesn’t release public symbols for every build, and sometimes the
symbols lag behind for a few months after release. Make sure you’re using an
mpengine version with public symbols available.
Use the following sample commandline to generate map and idb files.
> idaw -A -P+ -S"createmap.idc mpengine.map" mpengine.dll
If you generate the map files on Windows, you’ll get CRLF line terminators, fix
them like this:
When you run mpclient under gdb, it will detect a debugger and print the
commands you need to enter to teach gdb about the symbols:
$ gdb -q ./mpclient
(gdb) r testfile.txt
Starting program: mpclient
main(): GDB: add-symbol-file engine/mpengine.dll 0xf6af4008+0x1000
main(): GDB: shell bash genmapsym.sh 0xf6af4008+0x1000 symbols_19009.o < mpengine.map
main(): GDB: add-symbol-file symbols_19009.o 0
Program received signal SIGTRAP, Trace/breakpoint trap.
0x0804d213 in main (argc=1, argv=0xffffcc64, envp=0xffffcc6c) at mpclient.c:156
156 __debugbreak();
(gdb)
If you enter the commands it shows into gdb, you will have symbols available.
Note that
genmapsym.sh
assumes you’re using GNU awk.
(gdb) add-symbol-file engine/mpengine.dll 0xf6af4008+0x1000
add symbol table from file "engine/mpengine.dll" at
.text_addr = 0xf6af5008
Reading symbols from engine/mpengine.dll...done.
(gdb) shell bash genmapsym.sh 0xf6af4008+0x1000 symbols_19009.o < mpengine.map
(gdb) add-symbol-file symbols_19009.o 0
add symbol table from file "symbols_19009.o" at
.text_addr = 0x0
Reading symbols from symbols_19009.o...done.
(gdb) p as3_parsemetadata_swf_vars_t
$1 = {void (void)} 0xf6feb842 <as3_parsemetadata_swf_vars_t>
Then you can continue, and it will run as normal.
Breakpoints, watchpoints and backtraces all work as normal, although it may be
more reliable to use hardware breakpoints than software breakpoints.
To use hardware breakpoints in gdb, you just use hb
or hbreak
instead of
break
. Note that you only get a limited number of hardware breakpoints.
(gdb) b as3_parsemethodinfo_swf_vars_t
Breakpoint 1 at 0xf6feb8da
(gdb) c
Continuing.
main(): Scanning test/input.swf...
EngineScanCallback(): Scanning input
Breakpoint 1, 0xf6feb8da in as3_parsemethodinfo_swf_vars_t ()
(gdb) bt
#0 0xf6feb8da in as3_parsemethodinfo_swf_vars_t ()
#1 0xf6dbad7f in SwfScanFunc ()
#2 0xf6d73ec3 in UfsScannerWrapper__ScanFile_scanresult_t ()
#3 0xf6d6c9e3 in UfsClientRequest__fscan_SCAN_REPLY ()
#4 0xf6d6a818 in UfsNode__ScanLoopHelper_wchar_t ()
#5 0xf6d6a626 in UfsNode__Analyze_UfsAnalyzeSetup ()
#6 0xf6d71f7f in UfsClientRequest__AnalyzeLeaf_wchar_t ()
#7 0xf6d71bb9 in UfsClientRequest__AnalyzePath_wchar_t ()
#8 0xf6dbbd88 in std___String_alloc_std___String_base_types_char_std__allocator_char______Myptr_void_ ()
#9 0xf6d75e72 in UfsCmdBase__ExecuteCmd__lambda_c80a88e180c1f4524a759d69aa15f87e____lambda_c80a88e180c1f4524a759d69aa15f87e__ ()
Backtrace stopped: previous frame inner to this frame (corrupt stack?)
(gdb) x/3i $pc
=> 0xf6feb8da <as3_parsemethodinfo_swf_vars_t+7>: lea ebx,[edx+0x1c]
0xf6feb8dd <as3_parsemethodinfo_swf_vars_t+10>: push esi
0xf6feb8de <as3_parsemethodinfo_swf_vars_t+11>: mov edx,ebx
What about Wine and Winelib?
This project does not replace Wine or Winelib.
Winelib is used to port Windows C++ projects to Linux, and Wine is
intended to run full Windows applications. This project is intended to allow
native Linux code to load simple Windows DLLs.
The closest analogy would be ndiswrapper but for userspace.
Further Examples
- avscript — Loading another antivirus engine, demonstrates hooking and patching.
License
GPL2
Certainly, interfacing a Windows DLL from a Linux environment is a common challenge, and there are several potential solutions to bridge this gap. Here are some approaches you might consider:
1. Using
Wine
Wine
is a powerful and popular solution that allows running Windows applications on Linux. This includes the ability to load and use Windows DLLs. Here’s a step-by-step approach to using Wine:
Install Wine on your Linux system:
sudo apt-get update sudo apt-get install wine
Create a wrapper in
C/C++
that interfaces with the DLL using Wine:
- Write a Windows application that loads the DLL and provides a way to call the needed functions.
- You can then run this application in Wine and communicate with it via a method such as sockets.
Example:
#include <windows.h> // Function to load the DLL and call its function void call_dll_function() { HINSTANCE hinstLib = LoadLibrary(TEXT("path_to_your_dll.dll")); if (hinstLib != NULL) { typedef void (__stdcall *FunctionType)(); FunctionType function = (FunctionType) GetProcAddress(hinstLib, "FunctionName"); if (function != NULL) { function(); } FreeLibrary(hinstLib); } }
- Set up socket communication to command and control this application:
You can use a simple TCP/IP socket to communicate between your Linux application and the Windows application running under Wine.2. Using Cross-Platform Frameworks
Frameworks such as ZeroMQ or gRPC can manage communication between processes on different systems.
3. Virtual Machines or Containers
Running Windows in a VM or container might be another approach:
Using a Virtual Machine (VM)
- Set up a Windows VM using VirtualBox, VMware, or similar.
- On the VM, run a server application (via TCP or HTTP, for instance) that can load and execute the DLL functions.
- Communicate with the server application from your Linux application via network calls.
Using Docker (Windows Containers)
- Use Docker to run a Windows container.
- Inside the container, set up the environment to load and run the DLL.
- Expose the necessary ports and methods to communicate between your Linux host and the Windows container.
4. Custom Socket-Based Bridge
If the above solutions do not fit your needs, you could indeed go for a custom socket-based bridge:
Create a Windows Server:
- Write a simple Windows application that loads the DLL and listens for incoming socket connections. On each request, call the appropriate DLL function and send back the results.
Linux Client:
- Write a Linux client that connects to the Windows server, sends requests, and receives the responses.
Simple Example:
Windows Server (C++ using Winsock):
#include <winsock2.h> #include <windows.h> #include <iostream> #pragma comment(lib, "ws2_32.lib") void call_dll_function() { HINSTANCE hinstLib = LoadLibrary(TEXT("path_to_your_dll.dll")); if (hinstLib != NULL) { typedef void (__stdcall *FunctionType)(); FunctionType function = (FunctionType) GetProcAddress(hinstLib, "FunctionName"); if (function != NULL) { function(); } FreeLibrary(hinstLib); } } int main() { WSADATA wsaData; SOCKET listening = INVALID_SOCKET; SOCKET clientSocket = INVALID_SOCKET; sockaddr_in serverAddr; WSAStartup(MAKEWORD(2, 2), &wsaData); listening = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); serverAddr.sin_family = AF_INET; serverAddr.sin_port = htons(27015); serverAddr.sin_addr.s_addr = htonl(INADDR_ANY); bind(listening, (SOCKADDR*)&serverAddr, sizeof(serverAddr)); listen(listening, SOMAXCONN); while (true) { clientSocket = accept(listening, NULL, NULL); if (clientSocket != INVALID_SOCKET) { char recvbuf[512]; int recvResult = recv(clientSocket, recvbuf, 512, 0); if (recvResult > 0) { call_dll_function(); const char* response = "DLL function called successfully."; send(clientSocket, response, (int)strlen(response), 0); } closesocket(clientSocket); } } closesocket(listening); WSACleanup(); return 0; }
Linux Client (C):
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <arpa/inet.h> int main() { int sockfd = socket(AF_INET, SOCK_STREAM, 0); struct sockaddr_in server_addr; server_addr.sin_family = AF_INET; server_addr.sin_port = htons(27015); inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr); if (connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) == 0) { char sendbuf[] = "call_dll_function"; send(sockfd, sendbuf, strlen(sendbuf), 0); char recvbuf[512]; int recvResult = recv(sockfd, recvbuf, 512, 0); if (recvResult > 0) { printf("Received: %s\n", recvbuf); } } close(sockfd); return 0; }
Conclusion
Using the above methods, you can successfully create a bridge to call a Windows DLL from your Linux application. Note that each method has its own advantages and trade-offs, so pick the one that best fits your specific requirements and constraints.
Млин, повторюсь, ато получилось непонятно:
>>Использовать WineLib для перекомпиляции моей виндовой длл-ки. Я >>так понял, можно взять бинарную длл-ку без исходников, и WineLib >>может сделать из нее линуховый бинарник? >Так собственно и cделано в mplayer, xine, aviplayer….
Я тут рылся в документации WineLib и насколько я понял, WineLib позволяет делать Виндовые библиотеки под Линух только при наличии исходников. У меня же исходников длл-ки нет :(.
>Ну это совсем такой же случай, как и с плеерами, можно взять >рипнутый вине из любого плеера, который работает с дллками и >написать свой врапер, сошку слинкованную с libwine.a из рипнутого >wine, далее просто пишите свою программу, которая будет работать с >этой либой. Есть только одна проблема, может оказаться так, что в >рипнутой wine не будет нужных виндузячих API функций, тогда придется >их брать из полного wine, или вообще не парится и взять libwine из >полной версии wine сразу, это позволит использовать большое кол-во >виндузячих функций, а так же сетевую поддержку…. Звучит сложно…
Но, если другого варианта не будет, то придется так…
Vetalb ★
()
автор топика
- Ссылка
Тэвис Орманди (Tavis Ormandy), известный эксперт Google по безопасности, выложил на GitHub инструмент loadlibrary, который позволяет нативным Linux-программам загружать и вызывать функции из динамически подключаемых библиотек Windows (DLL). В качестве демонстрации Тэвис портировал антивирус Windows Defender на Linux.
Для каких целей подходит loadlibrary?
Тэвис уточнил, что библиотека loadlibrary создана скорее для исследователей проблем безопасности, чем для всего сообщества пользователей Linux:
Этот инструмент не заменяет Wine или Winelib. Winelib используется для портирования проектов Windows C++ на Linux, а Wine — для запуска полноценных Windows-приложений. Мой инструмент позволяет загружать простые Windows DLL.
Тем не менее, loadlibrary привлекательна для разработчиков: можно загружать DLL-данные в Linux-приложения без необходимости портировать Windows-приложение целиком.
Как с помощью loadlibrary можно исследовать системы безопасности?
Библиотека позволяет использовать DLL совместно с инструментами для фаззинга. При фаззинге приложению на вход передается произвольный набор данных, а затем вывод анализируется на предмет нарушений и неисправностей. Такой метод в том числе применяется в рамках тестирования на проникновение (пентестинга).
Google за последние годы сделала два популярных фаззера: OSS-Fuzz (недавно компания провела исследование эффективности его работы) и syzkaller. Последний помог обнаружить 3 крупных бага в ядре Linux (раз, два, три), первые 2 из которых жили там на протяжении нескольких лет. Это показывает способность фаззинга выявлять уязвимости, которые легко пропустить при классическом ручном тестировании.
Используя свою библиотеку, Тэвис недавно обнаружил «crazy bad» — уязвимость в ядре Microsoft Malware Protection Engine (MsMpEng), сервиса по обеспечению безопасности, предустановленного в Windows 8, 8.1, 10 и Windows Server 2016. Вчера исследователь портировал компонент пакета MsMpEng, отвечающий за сканирование и анализ зловредов — то есть, антивирус Windows Defender.
Инструмент и вся подробная информация о нем находится в репозитории на GitHub.
Cross-compiling a Windows DLL on Linux using Mingw
I am trying to deliver a Windows DLL (as well as a .so) from a Linux box using Mingw.
I am following this example, which consists of three files, the DLL source example_dll.cpp , header example_dll.h , and a client application example_exe.cpp . These I have located in a folder shared by my Linux host and Windows 7 VM. Both boxes have Mingw installed.
The build commands for the DLL are
- g++ -c -DBUILDING_EXAMPLE_DLL example_dll.cpp
- g++ -shared -o example_dll.dll example_dll.o -Wl,—out-implib,libexample_dll.a
and for the client app
- g++ -c example_exe.cpp
- g++ -o example_exe.exe example_exe.o -L. -lexample_dll
All compiles and runs perfectly on a Windows 7 VM with Mingw installed.
All compiles perfectly under Ubuntu 16.04 with Mingw installed, replacing g++ with i686-w64-mingw32-g++ .
But in this case, when the executable is run from the Windows VM, «The program can’t start because libgcc_s_sjlj-1.dll is missing.
- What mistake am I making?
I can force the «missing» DLLs into the executable, by replacing 4. with i686-w64-mingw32-g++ -o example_exe.exe example_exe.o -L. -lexample_dll -static-libgcc -static-libstdc++ on Linux, and that works perfectly on the Windows VM.
But I need to deliver a DLL, not an executable.
- I have noticed that the DLL libgcc_s_sjlj-1.dll exists on the Linux box but not the Windows box.
- I have also noticed that the Linux box has Mingw 5.3.1 while the Windows box has Mingw 6.3.0
Источник
Using Windows DLL from Linux
We need to interface to 3rd party app, but company behind the app doesn’t disclose message protocol and provides only Windows DLL to interface to.
Our application is Linux-based so I cannot directly communicate with DLL. I couldn’t find any existing solution so I’m considering writing socket-based bridge between Linux and Windows, however I’m sure it is not such a unique problem and somebody should have done it before.
Are you aware of any solution that allows to call Windows DDL functions from C app on Linux? It can use Wine or separate Windows PC — doesn’t matter.
Many thanks in advance.
7 Answers 7
I wrote a small Python module for calling into Windows DLLs from Python on Linux. It is based on IPC between a regular Linux/Unix Python process and a Wine-based Python process. Because I have needed it in too many different use-cases / scenarios myself, I designed it as a «generic» ctypes module drop-in replacement, which does most of the required plumbing automatically in the background.
Example: Assume you’re in Python on Linux, you have Wine installed, and you want to call into msvcrt.dll (the Microsoft C runtime library). You can do the following:
It’s still a bit rough around the edges (i.e. alpha and insecure), but it does handle most types of parameters (including pointers).
Any solution is going to need a TCP/IP-based «remoting» layer between the DLL which is running in a «windows-like» environment, and your linux app.
You’ll need to write a simple PC app to expose the DLL functions, either using a homebrew protocol, or maybe XML-RPC, SOAP or JSON protocols. The RemObjects SDK might help you — but could be overkill.
I’d stick with a ‘real’ or virtualized PC. If you use Wine, the DLL developers are unlikely to offer any support.
MONO is also unlikely to be any help, because your DLL is probably NOT a .NET assembly.
This is a common problem. Fortunately, it now has a solution. Meet LoadLibrary, developed by Tavis Ormandy:
I first stumbled across LoadLibrary in an article on Phoronix by Michael Larabel:
A Google researcher has been developing «LoadLibrary» as a means of being able to load Windows Dynamic Link Libraries (DLLs) that in turn can be used by native Linux code.
LoadLibrary isn’t a replacement for Wine or the like but is intended to allow Windows DLL libraries to be loaded that can then be accessed by native Linux code, not trying to run Windows programs and the like on Linux but simply loading the libraries.
This project is being developed by Tavis Ormandy, a well known Google employee focused on vulnerability research. He worked on a custom PE/COFF loader based on old ndiswrapper code, the project that was about allowing Windows networking drivers to function on Linux. LoadLibrary will handle relocations and imports and offers an API inspired by dlopen. LoadLibrary at this stage appears to be working well with self-contained Windows libraries and Tavis is using the project in part for fuzzing Windows libraries on Linux.
Tavis noted, «Distributed, scalable fuzzing on Windows can be challenging and inefficient. This is especially true for endpoint security products, which use complex interconnected components that span across kernel and user space. This often requires spinning up an entire virtualized Windows environment to fuzz them or collect coverage data. This is less of a problem on Linux, and I’ve found that porting components of Windows Antivirus products to Linux is often possible. This allows me to run the code I’m testing in minimal containers with very little overhead, and easily scale up testing.»
More details on LoadLibrary for loading Windows DLLs on Linux via GitHub where he also demonstrated porting Windows Defender libraries to Linux.
Источник
taviso/loadlibrary
Use Git or checkout with SVN using the web URL.
Work fast with our official CLI. Learn more.
Launching GitHub Desktop
If nothing happens, download GitHub Desktop and try again.
Launching GitHub Desktop
If nothing happens, download GitHub Desktop and try again.
Launching Xcode
If nothing happens, download Xcode and try again.
Launching Visual Studio Code
Your codespace will open once ready.
There was a problem preparing your codespace, please try again.
Latest commit
Git stats
Files
Failed to load latest commit information.
README.md
Porting Windows Dynamic Link Libraries to Linux
This repository contains a library that allows native Linux programs to load and call functions from a Windows DLL.
As a demonstration, I’ve ported Windows Defender to Linux.
How does it work?
The peloader directory contains a custom PE/COFF loader derived from ndiswrapper. The library will process the relocations and imports, then provide a dlopen -like API. The code supports debugging with gdb (including symbols), basic block coverage collection, and runtime hooking and patching.
The intention is to allow scalable and efficient fuzzing of self-contained Windows libraries on Linux. Good candidates might be video codecs, decompression libraries, virus scanners, image decoders, and so on.
- C++ exception dispatch and unwinding.
- Loading additional symbols from IDA.
- Debugging with gdb (including symbols), breakpoints, stack traces, etc.
- Runtime hooking and patching.
- Support for ASAN and Valgrind to detect subtle memory corruption bugs.
If you need to add support for any external imports, writing stubs is usually quick and easy.
Distributed, scalable fuzzing on Windows can be challenging and inefficient. This is especially true for endpoint security products, which use complex interconnected components that span across kernel and user space. This often requires spinning up an entire virtualized Windows environment to fuzz them or collect coverage data.
This is less of a problem on Linux, and I’ve found that porting components of Windows Antivirus products to Linux is often possible. This allows me to run the code I’m testing in minimal containers with very little overhead, and easily scale up testing.
This is just personal opinion, but I also think Linux has better tools. ¯\_(ツ)_/¯
MsMpEng is the Malware Protection service that is enabled by default on Windows 8, 8.1, 10, Windows Server 2016, and so on. Additionally, Microsoft Security Essentials, System Centre Endpoint Protection and various other Microsoft security products share the same core engine.
The core component of MsMpEng responsible for scanning and analysis is called mpengine. Mpengine is a vast and complex attack surface, comprising of handlers for dozens of esoteric archive formats, executable packers, full system emulators for various architectures and interpreters for various languages. All of this code is accessible to remote attackers.
To build the test client, simply type make .
Note that the .i686 or :i386 suffixes are important, we need the 32bit libraries to use the 32bit dll.
Fedora / RedHat | Ubuntu / Debian | Comment |
---|---|---|
glibc-devel.i686 | libc6-dev:i386 / libc6-dev-i386 | Name varies with version. |
libgcc.i686 | gcc-multilib | |
readline-devel.i686 | libreadline-dev:i386 | Optional, used in mpscript. |
cabextract | cabextract | Used to extract definitions. |
You will need to download the 32-bit antimalware update file from this page:
This should be a direct link to the right file:
This will download a file called mpam-fe.exe , which is a cabinet file that can be extracted with cabextract . Extract the files into the engine directory:
If you want to know which version you got, try this:
The main mpengine loader is called mpclient , it accepts filenames to scan as a parameter.
There are some other sample tools, mpstreamfuzz and mpscript .
If you want to debug a crash, single step through a routine or set breakpoints, follow these examples. First, you need a map file from IDA.
Microsoft doesn’t release public symbols for every build, and sometimes the symbols lag behind for a few months after release. Make sure you’re using an mpengine version with public symbols available.
Use the following sample commandline to generate map and idb files.
If you generate the map files on Windows, you’ll get CRLF line terminators, fix them like this:
When you run mpclient under gdb, it will detect a debugger and print the commands you need to enter to teach gdb about the symbols:
If you enter the commands it shows into gdb, you will have symbols available.
Note that genmapsym.sh assumes you’re using GNU awk.
Then you can continue, and it will run as normal.
Breakpoints, watchpoints and backtraces all work as normal, although it may be more reliable to use hardware breakpoints than software breakpoints.
To use hardware breakpoints in gdb, you just use hb or hbreak instead of break . Note that you only get a limited number of hardware breakpoints.
What about Wine and Winelib?
This project does not replace Wine or Winelib.
Winelib is used to port Windows C++ projects to Linux, and Wine is intended to run full Windows applications. This project is intended to allow native Linux code to load simple Windows DLLs.
The closest analogy would be ndiswrapper but for userspace.
Источник
Possible to use a .dll on Linux [duplicate]
Question: Is it possible to compile a program on linux using a .dll file?
Where this is going: This .dll will be used to write a php extension to some proprietary software from a third party.
Background and Research:
I have been given a library called proprietary.lib . I was curious, as I have never seen the .lib extension before, so I typed:
I did some research and found that ar is more-or-less tar (and in fact, I guess tar has since replaced ar in most *nix environments).
Upon inspecting the ar manpage, I saw the t option , which displays a table listing of the contents of that archive. Cool. So I type:
5 Answers 5
Recent development may have changed the situation: There is a loadlibrary function for Linux available, that makes it possible to load a Windows DLL and then call functions within.
So, if the .dll file you have actually is a Windows DLL, you may find a way to use it in you software.
You could try extracting the ar file (Debian packages are ar files, fwiw) and run file on the contents.
You’re not going to be able to use Windows DLLs without translation. The only DLL files that I know of that work natively on Linux are compiled with Mono.
If someone gave you a proprietary binary library to code against, you should verify it’s compiled for the target architecture (nothing like trying to use am ARM binary on an x86 system) and that it’s compiled for Linux.
That being said. good luck. I hate programming against third-party libraries where I have the documentation and the source.
Источник
yugr/Implib.so
Use Git or checkout with SVN using the web URL.
Work fast with our official CLI. Learn more.
Launching GitHub Desktop
If nothing happens, download GitHub Desktop and try again.
Launching GitHub Desktop
If nothing happens, download GitHub Desktop and try again.
Launching Xcode
If nothing happens, download Xcode and try again.
Launching Visual Studio Code
Your codespace will open once ready.
There was a problem preparing your codespace, please try again.
Latest commit
Git stats
Files
Failed to load latest commit information.
README.md
In a nutshell, Implib.so is a simple equivalent of Windows DLL import libraries for POSIX shared libraries.
On Linux/Android, if you link against shared library you normally use -lxyz compiler option which makes your application depend on libxyz.so . This would cause libxyz.so to be forcedly loaded at program startup (and its constructors to be executed) even if you never call any of its functions.
If you instead want to delay loading of libxyz.so (e.g. its unlikely to be used and you don’t want to waste resources on it or slow down startup time or you want to select best platform-specific implementation at runtime), you can remove dependency from LDFLAGS and issue dlopen call manually. But this would cause ld to err because it won’t be able to statically resolve symbols which are supposed to come from this shared library. At this point you have only two choices:
- emit normal calls to library functions and suppress link errors from ld via -Wl,-z,nodefs ; this is undesired because you loose ability to detect link errors for other libraries statically
- load necessary function addresses at runtime via dlsym and call them via function pointers; this isn’t very convenient because you have to keep track which symbols your program uses, properly cast function types and also somehow manage global function pointers
Implib.so provides an easy solution — link your program with a wrapper which
- provides all necessary symbols to make linker happy
- loads wrapped library on first call to any of its functions
- redirects calls to library symbols
Generated wrapper code (often also called «shim» code or «shim» library) is analogous to Windows import libraries which achieve the same functionality for DLLs.
Implib.so was originally inspired by Stackoverflow question Is there an elegant way to avoid dlsym when using dlopen in C?.
A typical use-case would look like this:
This will generate code for host platform (presumably x86_64). For other targets do
where TARGET can be any of
- x86_64-linux-gnu, x86_64-none-linux-android
- i686-linux-gnu, i686-none-linux-android
- arm-linux-gnueabi, armel-linux-gnueabi, armv7-none-linux-androideabi
- arm-linux-gnueabihf (ARM hardfp ABI)
- aarch64-linux-gnu, aarch64-none-linux-android
- mipsel-linux-gnu
- mips64el-linux-gnuabi64
- e2k-linux-gnu
Script generates two files: libxyz.so.tramp.S and libxyz.so.init.c which need to be linked to your application (instead of -lxyz ):
Note that you need to link against libdl.so. On ARM in case your app is compiled to Thumb code (which e.g. Ubuntu’s arm-linux-gnueabihf-gcc does by default) you’ll also need to add -mthumb-interwork .
Application can then freely call functions from libxyz.so without linking to it. Library will be loaded (via dlopen ) on first call to any of its functions. If you want to forcedly resolve all symbols (e.g. if you want to avoid delays further on) you can call void libxyz_init_all() .
Above command would perform a lazy load i.e. load library on first call to one of it’s symbols. If you want to load it at startup, run
If you don’t want dlopen to be called automatically and prefer to load library yourself at program startup, run script as
If you do want to load library via dlopen but would prefer to call it yourself (e.g. with custom parameters or with modified library name), run script as
(callback must have signature void *(*)(const char *lib_name) and return handle of loaded library).
Normally symbols are located via dlsym function but this can be overriden with custom callback by using —dlsym-callback (which must have signature void *(*)(void *handle, const char *sym_name) ).
Finally to force library load and resolution of all symbols, call
By default the tool does not try to wrap vtables exported from the library. This can be enabled via —vtables flag:
Reducing external interface of closed-source library
Sometimes you may want to reduce public interface of existing shared library (e.g. if it’s a third-party lib which erroneously exports too many unrelated symbols).
To achieve this you can generate a wrapper with limited number of symbols and override the callback which loads the library to use dlmopen instead of dlopen (and thus does not pollute the global namespace):
Similar approach can be used if you want to provide a common interface for several libraries with partially intersecting interfaces (see this example for more details).
Renaming exported interface of closed-source library
Sometimes you may need to rename API of existing shared library to avoid name clashes.
To achieve this you can generate a wrapper with renamed symbols which call to old, non-renamed symbols in original library loaded via dlmopen instead of dlopen (to avoid polluting global namespace):
Generation of wrappers may be automated via linker wrapper scripts/ld . Adding it to PATH (in front of normal ld ) would by default result in all dynamic libs (besides system ones) to be replaced with wrappers. Explicit list of libraries can be specified by exporting IMPLIBSO_LD_OPTIONS environment variable:
For more details run with
Atm linker wrapper is only meant for testing.
Implib.so overhead on a fast path boils down to
- predictable direct jump to wrapper
- predictable untaken direct branch to initialization code
- load from trampoline table
- predictable indirect jump to real function
This is very similar to normal shlib call:
- predictable direct jump to PLT stub
- load from GOT
- predictable indirect jump to real function
so it should have equivalent performance.
The tool does not transparently support all features of POSIX shared libraries. In particular
- it can not provide wrappers for data symbols (except C++ virtual/RTTI tables)
- it makes first call to wrapped functions asynch signal unsafe (as it will call dlopen and library constructors)
- it may change semantics if there are multiple definitions of same symbol in different loaded shared objects (runtime symbol interposition is considered a bad practice though)
- it may change semantics because shared library constructors are delayed until when library is loaded
The tool also lacks the following important features:
- proper support for multi-threading
- symbol versions are not handled at all
- support OSX (none should be hard to add so let me know if you need it).
Finally, there are some minor TODOs in code.
As mentioned in introduction import libraries are first class citizens on Windows platform:
Delay-loaded libraries were once present on OSX (via -lazy_lXXX and -lazy_library options).
Lazy loading is supported by Solaris shared libraries but was never implemented in Linux. There have been some discussions in libc-alpha but no patches were posted.
Implib.so-like functionality is used in OpenGL loading libraries e.g. GLEW via custom project-specific scripts.
About
POSIX equivalent of Windows DLL import libraries
Источник