{"id":13438077,"url":"https://github.com/taviso/loadlibrary","last_synced_at":"2025-05-13T20:22:13.470Z","repository":{"id":40336163,"uuid":"92219431","full_name":"taviso/loadlibrary","owner":"taviso","description":"Porting Windows Dynamic Link Libraries to Linux","archived":false,"fork":false,"pushed_at":"2025-04-10T12:30:38.000Z","size":1235,"stargazers_count":4388,"open_issues_count":43,"forks_count":382,"subscribers_count":161,"default_branch":"master","last_synced_at":"2025-04-28T11:57:22.393Z","etag":null,"topics":["linux","porting","windows"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/taviso.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2017-05-23T20:54:39.000Z","updated_at":"2025-04-28T08:18:54.000Z","dependencies_parsed_at":"2025-04-11T11:40:08.285Z","dependency_job_id":null,"html_url":"https://github.com/taviso/loadlibrary","commit_stats":{"total_commits":90,"total_committers":13,"mean_commits":6.923076923076923,"dds":0.4666666666666667,"last_synced_commit":"c40033b12fd82514f8ee4e42a25906b773b91b5c"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/taviso%2Floadlibrary","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/taviso%2Floadlibrary/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/taviso%2Floadlibrary/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/taviso%2Floadlibrary/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/taviso","download_url":"https://codeload.github.com/taviso/loadlibrary/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251311332,"owners_count":21569008,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["linux","porting","windows"],"created_at":"2024-07-31T03:01:02.730Z","updated_at":"2025-04-28T11:57:29.976Z","avatar_url":"https://github.com/taviso.png","language":"C","readme":"# Porting Windows Dynamic Link Libraries to Linux\n## Introduction\n\nThis repository contains a library that allows native Linux programs to load\nand call functions from a Windows DLL.\n\nAs a demonstration, I've ported Windows Defender to Linux.\n\n```\n$ ./mpclient eicar.com\nmain(): Scanning eicar.com...\nEngineScanCallback(): Scanning input\nEngineScanCallback(): Threat Virus:DOS/EICAR_Test_File identified.\n```\n\n### How does it work?\n\nThe `peloader` directory contains a custom PE/COFF loader derived from\nndiswrapper. The library will process the relocations and imports, then provide\na `dlopen`-like API. The code supports debugging with gdb (including symbols),\nbasic block coverage collection, and runtime hooking and patching.\n\n![Is such a thing even possible?](https://media.giphy.com/media/2pDSW8QQU6jRe/giphy.gif)\n\n### What works?\n\nThe intention is to allow scalable and efficient fuzzing of self-contained\nWindows libraries on Linux. Good candidates might be video codecs,\ndecompression libraries, virus scanners, image decoders, and so on.\n\n* C++ exception dispatch and unwinding.\n* Loading additional symbols from IDA.\n* Debugging with gdb (including symbols), breakpoints, stack traces, etc.\n* Runtime hooking and patching.\n* Support for ASAN and Valgrind to detect subtle memory corruption bugs.\n\nIf you need to add support for any external imports, writing stubs is usually\nquick and easy.\n\n### Why?\n\nDistributed, scalable fuzzing on Windows can be challenging and inefficient.\nThis is especially true for endpoint security products, which use complex\ninterconnected components that span across kernel and user space. This\noften requires spinning up an entire virtualized Windows environment to fuzz\nthem or collect coverage data.\n\nThis is less of a problem on Linux, and I've found that porting components of\nWindows Antivirus products to Linux is often possible. This allows me to run\nthe code I’m testing in minimal containers with very little overhead, and\neasily scale up testing.\n\nThis is just personal opinion, but I also think Linux has better tools. `¯\\_(ツ)_/¯`\n\n## Windows Defender\n\nMsMpEng is the Malware Protection service that is enabled by default on Windows\n8, 8.1, 10, Windows Server 2016, and so on. Additionally, Microsoft Security\nEssentials, System Centre Endpoint Protection and various other Microsoft\nsecurity products share the same core engine.\n\nThe core component of MsMpEng responsible for scanning and analysis is called\nmpengine. Mpengine is a vast and complex attack surface, comprising of handlers\nfor dozens of esoteric archive formats, executable packers, full system\nemulators for various architectures and interpreters for various languages. All\nof this code is accessible to remote attackers.\n\n### Building\n\nTo build the test client, simply type `make`.\n\n```\n$ make\n```\n\n### Dependencies\n\n*Note that the `.i686` or `:i386` suffixes are important, we need the 32bit libraries to use the 32bit dll.*\n\n| Fedora / RedHat       | Ubuntu / Debian                     | Comment                      |\n| --------------------- | ----------------------------------- |:---------------------------- |\n| `glibc-devel.i686`    | `libc6-dev:i386` / `libc6-dev-i386` | Name varies with version.    |\n| `libgcc.i686`         | `gcc-multilib`                      |                              |\n| `readline-devel.i686` | `libreadline-dev:i386`              | Optional, used in mpscript.  |\n| `cabextract`          | `cabextract`                        | Used to extract definitions. |\n\nYou will need to download the 32-bit antimalware update file from this page:\n\n* https://www.microsoft.com/security/portal/definitions/adl.aspx#manual\n\nThis should be a direct link to the right file:\n\n* https://go.microsoft.com/fwlink/?LinkID=121721\u0026arch=x86\n\nThis will download a file called `mpam-fe.exe`, which is a cabinet file that\ncan be extracted with `cabextract`. Extract the files into the `engine`\ndirectory:\n\n```\n$ cabextract mpam-fe.exe\nExtracting cabinet: mpam-fe.exe\n  extracting MPSigStub.exe\n  extracting mpavdlta.vdm\n  extracting mpasdlta.vdm\n  extracting mpavbase.vdm\n  extracting mpasbase.vdm\n  extracting mpengine.dll\n\nAll done, no errors.\n```\n\nIf you want to know which version you got, try this:\n\n```\n$ exiftool mpengine.dll | grep 'Product Version Number'\nProduct Version Number          : 1.1.13701.0\n```\n\n### Running\n\nThe main mpengine loader is called `mpclient`, it accepts filenames to scan as\na parameter.\n\n```\n$ ./mpclient netsky.exe\nmain(): Scanning netsky.exe...\nEngineScanCallback(): Scanning input\nEngineScanCallback(): Threat Worm:Win32/Netsky.P@mm identified.\n```\n\nThere are some other sample tools, `mpstreamfuzz` and `mpscript`.\n\n### Debugging\n\nIf you want to debug a crash, single step through a routine or set breakpoints,\nfollow these examples. First, you need a map file from IDA.\n\nMicrosoft doesn't release public symbols for every build, and sometimes the\nsymbols lag behind for a few months after release. Make sure you're using an\nmpengine version with public symbols available.\n\nUse the following sample commandline to generate map and idb files.\n\n```\n\u003e idaw -A -P+ -S\"createmap.idc mpengine.map\" mpengine.dll\n```\n\nIf you generate the map files on Windows, you'll get CRLF line terminators, fix\nthem like this:\n\n```\n$ dos2unix mpengine.map\n```\n\nWhen you run mpclient under gdb, it will detect a debugger and print the\ncommands you need to enter to teach gdb about the symbols:\n\n```\n$ gdb -q ./mpclient\n(gdb) r testfile.txt\nStarting program: mpclient\nmain(): GDB: add-symbol-file engine/mpengine.dll 0xf6af4008+0x1000\nmain(): GDB: shell bash genmapsym.sh 0xf6af4008+0x1000 symbols_19009.o \u003c mpengine.map\nmain(): GDB: add-symbol-file symbols_19009.o 0\n\nProgram received signal SIGTRAP, Trace/breakpoint trap.\n0x0804d213 in main (argc=1, argv=0xffffcc64, envp=0xffffcc6c) at mpclient.c:156\n156\t        __debugbreak();\n(gdb)\n```\n\nIf you enter the commands it shows into gdb, you will have symbols available.\n\n\u003e *Note that `genmapsym.sh` assumes you're using GNU awk.*\n\n```\n(gdb) add-symbol-file engine/mpengine.dll 0xf6af4008+0x1000\nadd symbol table from file \"engine/mpengine.dll\" at\n\t.text_addr = 0xf6af5008\nReading symbols from engine/mpengine.dll...done.\n(gdb) shell bash genmapsym.sh 0xf6af4008+0x1000 symbols_19009.o \u003c mpengine.map\n(gdb) add-symbol-file symbols_19009.o 0\nadd symbol table from file \"symbols_19009.o\" at\n\t.text_addr = 0x0\nReading symbols from symbols_19009.o...done.\n(gdb) p as3_parsemetadata_swf_vars_t\n$1 = {void (void)} 0xf6feb842 \u003cas3_parsemetadata_swf_vars_t\u003e\n```\n\nThen you can continue, and it will run as normal.\n\n```\n(gdb) c\n```\n\nBreakpoints, watchpoints and backtraces all work as normal, although it may be\nmore reliable to use hardware breakpoints than software breakpoints.\n\nTo use hardware breakpoints in gdb, you just use `hb` or `hbreak` instead of\n`break`. Note that you only get a limited number of hardware breakpoints.\n\n```\n(gdb) b as3_parsemethodinfo_swf_vars_t\nBreakpoint 1 at 0xf6feb8da\n(gdb) c\nContinuing.\nmain(): Scanning test/input.swf...\nEngineScanCallback(): Scanning input\nBreakpoint 1, 0xf6feb8da in as3_parsemethodinfo_swf_vars_t ()\n(gdb) bt\n#0  0xf6feb8da in as3_parsemethodinfo_swf_vars_t ()\n#1  0xf6dbad7f in SwfScanFunc ()\n#2  0xf6d73ec3 in UfsScannerWrapper__ScanFile_scanresult_t ()\n#3  0xf6d6c9e3 in UfsClientRequest__fscan_SCAN_REPLY ()\n#4  0xf6d6a818 in UfsNode__ScanLoopHelper_wchar_t ()\n#5  0xf6d6a626 in UfsNode__Analyze_UfsAnalyzeSetup ()\n#6  0xf6d71f7f in UfsClientRequest__AnalyzeLeaf_wchar_t ()\n#7  0xf6d71bb9 in UfsClientRequest__AnalyzePath_wchar_t ()\n#8  0xf6dbbd88 in std___String_alloc_std___String_base_types_char_std__allocator_char______Myptr_void_ ()\n#9  0xf6d75e72 in UfsCmdBase__ExecuteCmd__lambda_c80a88e180c1f4524a759d69aa15f87e____lambda_c80a88e180c1f4524a759d69aa15f87e__ ()\nBacktrace stopped: previous frame inner to this frame (corrupt stack?)\n(gdb) x/3i $pc\n=\u003e 0xf6feb8da \u003cas3_parsemethodinfo_swf_vars_t+7\u003e:\tlea    ebx,[edx+0x1c]\n   0xf6feb8dd \u003cas3_parsemethodinfo_swf_vars_t+10\u003e:\tpush   esi\n   0xf6feb8de \u003cas3_parsemethodinfo_swf_vars_t+11\u003e:\tmov    edx,ebx\n```\n\n## What about Wine and Winelib?\n\nThis project does not replace Wine or Winelib.\n\nWinelib is used to port Windows C++ projects to Linux, and Wine is\nintended to run full Windows applications. This project is intended to allow\nnative Linux code to load simple Windows DLLs.\n\nThe closest analogy would be ndiswrapper but for userspace.\n\n## Further Examples\n\n* [avscript](https://github.com/taviso/avscript) - Loading another antivirus engine, demonstrates hooking and patching.\n\n## License\n\nGPL2\n\n","funding_links":[],"categories":["C","Development"],"sub_categories":["VoIP"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftaviso%2Floadlibrary","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftaviso%2Floadlibrary","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftaviso%2Floadlibrary/lists"}