/ Windows / 156浏览

如何从头开始写一个 Native App

引言

在 Windows 中,我们的进程通常都运行在一个叫 Windows 的子系统上。在 Windows 子系统上分为 console、GUI 等子系统。进程如果想要调用系统 API,通常都需要先调用子系统的 API,来做一次转换。简单结构如下:

而这里我们说的 Native App 呢,它是不依赖任何子系统,可以直接通过 ntdll.dll 来调用系统 API 的。简单结构如下:

Native App 的优势

对比普通的 Win32 或者说其他子系统应用,主要有以下几个优势

  • 性能好。使用 native 接口,可以绕过标准 Windows 应用程序接口,从而去掉一个软件层,可以加快运行速度。
  • 功能强大。标准 Windows Api 无法提供的功能,也可能通过 Native Api 来实现。
  • 依赖少。不依赖子系统的 dll,减少很多依赖。
  • 灵活性好。此应用不依赖子系统,所以不用等子系统启动后才能运行。

开发 Hello Native

创建项目

VS 中是没有 native 应用的模板的,所以这里我们先创建一个 console app,然后基于 cosnole app 来进行修改部分配置即可。

创建完成后,选择项目,鼠标右键弹出菜单,选择【属性】,如下图:

开始修改配置

按如下图配置,依次修改:

然后我们要处理一下默认依赖了:

首先将 【Ignore All Default Libraries】选择【Yes】

然后,添加其他的依赖。

这里需要注意的是,由于在标准的 ntdll.lib 中没有列出 ntdll.dll 中实现的 CRT 函数,因此链接可能出现问题。所以这里我们采用一个三方库:

Clone 下来,编译下就好了:

cd ntdll
nmake msvc

编译后,会生成 ntdll64.libntdll86.lib 。在 Windows 64 位系统上,选择 ntdll64.lib 即可。然后再 额外依赖中添加对应的 lib 文件即可。

$(CoreLibraryDependencies)
%(AdditionalDependencies)
"D:libntdll64.lib"

总体配置如下:

💡 这里也可以通过 LdrGetDllHandleLdrGetProcedureAddress 来做。但相对比较麻烦。如果不需要用到 swprintf_s 是不需要这一步的,用普通的 ntdll.dll 就可以

开始写代码

不同于普通应用,Native App 的入口函数是 NtProcessStartup ,这里我们给出简单的示例:

#include <phnt_windows.h>
#include <phnt.h>

extern "C" int swprintf_s(
    wchar_t* _Buffer, USHORT size,
    wchar_t const* _Format, ...);

NTSTATUS NtProcessStartup(PPEB peb) {
    RTL_OSVERSIONINFOEXW osvi = { sizeof(osvi) };
    RtlGetVersion(&osvi);

    WCHAR text[256];
    swprintf_s(text, ARRAYSIZE(text), L"Windows version: %d.%d.%dn",
        osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber);

    UNICODE_STRING str;
    RtlInitUnicodeString(&str, text);
    NtDrawText(&str);

    LARGE_INTEGER li;
    li.QuadPart = -10000000 * 10;
    NtDelayExecution(FALSE, &li);

    return STATUS_SUCCESS;
}

这里逻辑是先获取系统版本号,然后将它打印在屏幕上。

有读者可能会好奇,phnt_windows 和 phnt 是什么?

由于 Windows 中各种头文件的依赖,所以直接采用一个三方的头文件库。

通过 vcpkg.exe 安装 phnt

  • clone 源代码
git clone https://github.com/Microsoft/vcpkg.git
  • 运行安装脚本
cd vcpkg
.bootstrap-vcpkg.bat
  • 集成到 VS
.vcpkg.exe integrate install
  • 安装 phnt
.vcpkg.exe install phnt

编译

然后就可以编译通过啦。会得到一个 exe 文件。如下图:

怎么跑起来

当你双击这个 exe 尝试运行的时候,会发现根本无法运行。

这是因为 Native app 没法在子系统模式下运行。这里我们可以参考 autochk 的运行方式。

将 exe 文件拷贝到 system32 文件夹中,然后再打开注册表编辑器,切换到 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager ,在 BootExecute key 上添加一个 HelloNative。如下图:

然后重启,就可以看到在用户登录之前,显示 Windows 版本的提示了。

也就是我们的第一个 native app。

【译】ETW 堆跟踪 – 每个分配都被记录
【译】ETW 堆跟踪 – 每个分配都被记录
【译】Wait Analysis – 寻找空闲时间
【译】Wait Analysis – 寻找空闲时间
如何通过 ETW Provider 来记录应用日志
如何通过 ETW Provider 来记录应用日志
如何通过 C++ 实时监听 ETW 事件
如何通过 C++ 实时监听 ETW 事件
【译】调查并确定 Windows 运行速度变慢问题
【译】调查并确定 Windows 运行速度变慢问题
【译】丢失的 WPA 文档 —— 磁盘使用
【译】丢失的 WPA 文档 —— 磁盘使用

0

  1. This post has no comment yet

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注