Wine源码中添加新的DLL模块

这篇具有很好参考价值的文章主要介绍了Wine源码中添加新的DLL模块。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Wine源码中添加新的DLL模块

1. 基础环境准备

编译环境:debootstrap 安装 debian bullseye
源码版本:Wine 9.0-rc4
基础环境搭建

2. 创建DLL模块目录

在dlls目录下新建一个文件夹:nfs
将amsi目录下的三个文件全部复制到nfs目录下:

main.c 文件内容中新加一个函数如下:

BOOLEAN WINAPI Test_In_CreateWindowEx( const WCHAR *classname, ULONG*  style, ULONG*  dwExStyle )
{
    TRACE( "classname=%s, style=0x08x, style=0x08x \n", debugstr_w(classname), style,  dwExStyle);
    return TRUE;
}

spec文件改名为nfs.spec, 将上面实现的函数导出给外部调用,nfs.spec内容如下:

@ stdcall Test_In_CreateWindowEx(ptr ptr ptr)

Makefile.in文件内容如下:(IMPORTLIB是为了生成.a文件)

MODULE    = nfs.dll
UNIXLIB   = nfs.so
IMPORTLIB = nfs

SOURCES = \
	main.c

3. 修改配置文件

将源码根目录下的 configure和configure.ac两个文件的权限改为可以编辑。

chmod 777 ./configure
chmod 777 ./configure.ac

打开configure.ac 文件找到dlls/amsi配置所在的行,按其样式,在他下方添加新的模块名

...
WINE_CONFIG_MAKEFILE(dlls/amsi)
WINE_CONFIG_MAKEFILE(dlls/nfs)
...

修改完成后,执行autoconf命令,重新生成configure文件,文件中会包含如下内容:

...
wine_fn_config_makefile dlls/nfs enable_nfs
...

4. 验证配置文件

执行./configure

...
configure: Finished.  Do 'make' to compile Wine.

运行成功后,在dlls/nfs目录下可以看到,一个名为Makefile的文件生成出来, 文件内容如下:

all:
all install install-lib clean i386-windows/main.o i386-windows/nfs.dll:
	@cd ../.. && $(MAKE) dlls/nfs/$@
.PHONY: all install install-lib clean

5. user32模块中调用

如果要在user32模块中调用新加的DLL中的函数,编辑dlls/user32/Makefile.in文件,将nfs加到IMPORTS后。

IMPORTS   = $(PNG_PE_LIBS) gdi32 sechost advapi32 kernelbase win32u nfs

dlls/user32/win.c文件中, 声明一下Test_In_CreateWindowEx方法,然后在WIN_CreateWindowEx方法内就可以直接调用了。

5. winex11drv模块中调用

5.1 添加头文件

在winex11drv模块中调用自定义模块的函数时,需要添加函数的声明头文件test.h,然后将test.h文件放到wine代码中的include目录下,同时需要在include/Makefile.in中添加头文件,不然会编译出错,提示找不到头文件。

5.2 共享库中对外函数的实现

当使用上述同样的方法,在winex11drv中调用我们自定义的nfs时,会发现在link时会报错说找不到函数的实现,这是因为winex11drv 中如果调用其它的模块时,实际上调用的是被调用模块的so文件,因此需要显示的将so文件加到winex11drv/makefile.in 文件的UNIX_LIBS后边。

UNIX_LIBS = -lwin32u $(X_LIBS) $(X_EXTRA_LIBS) $(PTHREAD_LIBS) -lm -lnfs

添加完后编译还是会提示找不到,使用nm来查看so中我们添加的函数时,可以看到函数是加进去了,但是修饰符号是小写的t,表示你编入so文件中的函数是仅限模块内部使用,其实在configure中可以看到, wine在编译时会默认加上下边的选项:

CFLAGS="$CFLAGS -fvisibility=hidden"

如果需要so中的函数定义在外部模块使用,需要显示的将函数声明为 attribute_((visibility (“default”))), 加好后重新编译,再用nm来查看生成的so文件时,可以看到编入so的函数的修饰符由小写的t变为大写的T了,这时就允许外部调用了。

5.3 映射dll中的声明到so

wine中的dll是用来模拟windows调用的,实际执行时还是要运行对应的windows代码,因此dlls中的函数通常是fake的,也就是说需要建立一个dll中函数调用时,映射到对so中的linux函数的调用。
如果要生成.so文件,单纯的添加UNIXLIB = nfs.so,是无法加入函数的实现的。
首选创建一个test_so.c,然后在文件中添加函数test_so_fun(),
为了让test_so.c生成的目标文件不放到i386-windows中,需要在文件顶部添加一段代码:

#if 0
#pragma makedep unix
#endif

然后将导出函数添加到spec文件中,如果没有syscall修饰可能生成失败:

@ stdcall -syscall test_so_fun()

最后将 test_so.c 加到Makefile.in中;

这时执行如下编译命令:

configure && make -j16

会报错,提示找不到test_so_fun的实现,原因是: 生成的dll文件是在i386-windows目录生成的,然后包含了实现的目标文件 test_so.o 并不在 i386-windows中,而是在模块的根目录dlls/nfs下,此时 nfs.so 中包含了test_so_fun的实现。
那么如何才能编译通过,并使其调用时链接到nfs.so 中的实现,就是要解决的问题。
通过对比可以发现,win32u模块中可以编译通过是因为有如下的代码:

//win32syscalls.h
#define ALL_SYSCALLS32 \
    SYSCALL_ENTRY( 0x0000, NtGdiAbortDoc, 4 ) \
    SYSCALL_ENTRY( 0x0001, NtGdiAbortPath, 4 ) \
    SYSCALL_ENTRY( 0x0002, NtGdiAddFontMemResourceEx, 20 ) \

因此我们使用一下wine源码中tools目录下的 make_specfiles 在wine源码的根目录执行后,会通过spec文件中指定的函数,自动生成上述的定义。
接下来需要在dlls/nfs/main.c文件中添加引用代码:

void *__wine_syscall_dispatcher = NULL;
static unixlib_handle_t nfs_handle;

#ifdef _WIN64
#define SYSCALL_ENTRY(id,name,args) __ASM_SYSCALL_FUNC( id + 0x1000, name )
ALL_SYSCALLS64
#else
#define SYSCALL_ENTRY(id,name,args) __ASM_SYSCALL_FUNC( id + 0x2000, name, args )
DEFINE_SYSCALL_HELPER32()
ALL_SYSCALLS32
#endif
#undef SYSCALL_ENTRY


BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, void *reserved )
{
    HMODULE ntdll;
    void **dispatcher_ptr;
    const UNICODE_STRING ntdll_name = RTL_CONSTANT_STRING( L"ntdll.dll" );
    switch (reason)
    {
    case DLL_PROCESS_ATTACH:
        LdrDisableThreadCalloutsForDll( inst );
        if (__wine_syscall_dispatcher) break;  /* already set through Wow64Transition */
        LdrGetDllHandle( NULL, 0, &ntdll_name, &ntdll );
        dispatcher_ptr = RtlFindExportedRoutineByName( ntdll, "__wine_syscall_dispatcher" );
        __wine_syscall_dispatcher = *dispatcher_ptr ;
        if (!NtQueryVirtualMemory( GetCurrentProcess(), inst, MemoryWineUnixFuncs,
                                   &nfs_handle, sizeof(nfs_handle), NULL ))
            __wine_unix_call( nfs_handle, 0, NULL );
        break;
        case DLL_PROCESS_DETACH:
           break;
    }
    return TRUE;
}

这些都完成后,编译就可以通过了,编译出来的nfs.dll和nfs.so可以用nm来查看一下,都包含了test_so_fun

6. 新加模块的初始化

先简单说明一下启动流程:

loader模块: main函数: 加载ntdll.so -> 执行dlsym( handle, "__wine_main" ) -> 调用dlls/ntdll模块中的 __wine_main
dlls/ntdll 模块: __wine_main函数:  check_command_line -> loader_exec -> start_main_thread -> load_ntdll

load_ntdll模块启动后,它会负责加载其它的dll模块,大部分模块在被ntrdll加载时会调用模块内的__wine_unix_call_funcs数据中的函数指针,数据中的函数指针对应的函数都会顺序执行。类似如下这种:

const unixlib_entry_t __wine_unix_call_funcs[] =
{
    init1,
    init2,
    init3,
};

这个__wine_unix_call_funcs数组之所以能被调用是因为每一个dll模块dllmain的执行时触发的,具体流程如下:
Wine源码中添加新的DLL模块,Wine,linux
可以将需要初始化的操作放到相关的init中,你可以自己尝试一下如何将新加的模块也放入ntdll中来启动。

7. 新加模块中调用其它模块

这个问题需要区分要调用的其它模块是so形式还是i386下.a或.dll形式, 如果在user32模块调用,可以发现直接修改Makefile.in中IMPORTS加上要引用的新模块就可以直接使用了,但是如果是win32u中,可以发现无法直接使用,因为win32u还要生成so文件,因此会提示找不到新模块中的函数定义,猜猜应该如何解决?文章来源地址https://www.toymoban.com/news/detail-792825.html

到了这里,关于Wine源码中添加新的DLL模块的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Manjaro(Ubuntu) 安装全新 Linux 版微信,从此告别 Wine

    目前已经基本上使用 Manjaro 来工作,而工作离不开微信作为日常的工作沟通工具。因为微信官方一直没有 Linux 版本的,所以之前都只能够使用 Wine 版本,然后踩了不少坑,但还算能勉强使用。 最近听说微信终于要发布 Linux 版本的,于是找了一些教程,还有踩了一些坑,最终

    2024年04月15日
    浏览(54)
  • Linux中_使用wine_软件_安装使用windows软件

    如果文件内容正确,可以将其复制到~/.local/share/applications目录中,以使其在应用程序菜单中可见。 如果还不行,可以尝试使用chmod命令赋予该文件执行权限,并使用./文件名运行该文件,运行exe软件。

    2024年02月09日
    浏览(35)
  • Ubuntu22.04安装微信Linux版(非Wine版)+中文输入

    Ubuntu下安装微信,一直是开发者痛点问题。微信终于推出了Linux原生版本(内侧版)。 我已经将资源上传至: https://download.csdn.net/download/dengtonglong/89003661 评论区有网盘的版本。 可能会提示缺少libssl1.1: 卸载: 刚安装没法使用输入法,由于我的输入法是ibus,官方建议使用f

    2024年04月17日
    浏览(40)
  • 给对象添加新的属性

    使用点 使用方括号 使用assign 也以用来复制对象。 扩展运算符 ES6新增语法,可以将两个对象合并成一个对象。

    2024年02月12日
    浏览(36)
  • Kali linux安装wine兼容层在kali上使用windows版微信

    Kali Linux 是专用于渗透测试及取证的 Linux 操作系统,是一种基于Debian的Linux发行版,由 BackTrack 发展而来,在整合了IWHAX、WHOPPIX和Auditor这三种渗透测试专用Live Linux后,BackTrack正式改名为KaliLInux,Kali Linux为满足 专业渗透测试 和 安全审核 的要求而设计,包含 600 多款工具软件,

    2024年02月09日
    浏览(48)
  • Proteus添加新的元件库

    在这个网站里我们可以搜索自己需要的元件下载: https://componentsearchengine.com 下载找到下载之后路径并解压 打开Proteus 点击库,选择Import parts 点击Select File,找到下载库文件路径。 打开,找到Proteus文件夹 选择.pdif后缀文件 可以看到已经出现了对应的原理图与封装,然后我们选

    2023年04月11日
    浏览(39)
  • 详细讲解FuzzBench如何添加新的Fuzzer

    最近几天一直在弄FuzzBench添加新的fuzzer,在添加过程中遇到各种问题,在此做详细记录。 这一部分可以直接参考此链接FuzzBench预备条件 1.拉取代码到本地 git clone https://github.com/google/fuzzbench cd fuzzbench git submodule update --init 2.安装fuzzbench sudo apt-get install build-essential 3.安装fuzzben

    2023年04月18日
    浏览(35)
  • Midjourney教程之添加新的服务器

    1.1 登录discord账号 目前的Midjourney 已经不再提供免费版了,使用的话需要定制高级会员,可以私信博主: 1.2 点击添加服务器,创建新服务器 , 弹出窗口点击亲自创建 1.3 点击仅供我和我的朋友使用 1.4 自定义服务器名称 2.1 将midjourney bot添加到刚刚建好的新的服务器 2.2 在弹出

    2024年02月09日
    浏览(34)
  • Leanback(1)-播放控制栏下添加新的行

      我们要在播放控制栏下面加入下面一行。 这个就是标准的row。 leanback的原理 Android Leanback结构源码简析 - 简书 我们知道Row用来提供数据,row可以通过一个ObjectAdapter来管理和提供数据 我们知道presenter是一个负责将数据绑定到视图上的对象,它可以根据不同的数据类型创建不

    2024年02月01日
    浏览(30)
  • J-Flash烧录工具如何添加新的芯片类型

      !--                   --   !-- CMS --   !--                   --   Device     ChipInfo Vendor=\\\"CMS32\\\" Name=\\\"CMS32L051\\\" Core=\\\"JLINK_CORE_CORTEX_M0\\\" WorkRAMAddr=\\\"0x20000000\\\" WorkRAMSize=\\\"0x2000\\\" /     FlashBankInfo Name=\\\"Internal Flash\\\" BaseAddr=\\\"0x00000000\\\" MaxSize=\\\"0x00010000\\\" Loader=\\\"Devices/CMS32/CMS32L051GE.FLM\\\" LoaderType=\\\"FLA

    2024年02月16日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包