/ Windows / 117浏览

如何从头开始写一个 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。

如何通过 C++ 实时监听 ETW 事件
如何通过 C++ 实时监听 ETW 事件
【译】调查并确定 Windows 运行速度变慢问题
【译】调查并确定 Windows 运行速度变慢问题
【译】丢失的 WPA 文档 —— 磁盘使用
【译】丢失的 WPA 文档 —— 磁盘使用
【译】丢失的 WPA 文档 —— CPU 调度
【译】丢失的 WPA 文档 —— CPU 调度
【译】丢失的 WPA 文档 —— CPU 采样
【译】丢失的 WPA 文档 —— CPU 采样
如何通过 PDH(Performance Data Helper) 获取性能计数器的值

0

  1. This post has no comment yet

发表回复

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