Reversing-kr-Windows-kernal
· 1 分钟阅读 · @admin

运行程序后发现,在输入数据之前需要先点击 Enable 按钮。
点击后按钮变为 Check,此时编辑框可以输入字符。输入正确的字符串后会弹出成功提示。
使用 IDA 载入程序进行分析,在 sub_401110 函数中找到了对输入字符串进行验证的关键逻辑。
跟进关键 call,可以看到这段代码是用户模式程序与内核驱动进行交互的部分。字符串验证的核心逻辑应该在驱动文件中实现。
使用 IDA 载入驱动文件进行分析:
驱动注册了两个派遣例程,其中 sub_11288 函数对应 DeviceIoControl,负责处理用户模式程序与驱动的交互。
分析可知,该函数处理 DeviceIoControlCode 为 0x1000 和 0x2000 的两种控制码。结合前面 sub_401110 函数的代码,可以理解程序的工作流程:
- 程序启动时,编辑框不可输入
- 点击 Enable 按钮,发送控制码 0x1000 到驱动,按钮文本变为 Check,编辑框变为可输入状态
- 输入字符后点击 Check,发送控制码 0x2000 到驱动进行验证
查看 sub_112F8 函数的具体代码:
驱动还使用 KeInitializeDpc 函数注册了一个定时器,定时执行 sub_11266 函数。在该函数中,我发现了关键的 READ_PORT_UCHAR 函数,它通过端口号读取输入的字节。读取后的数据在 sub_111DC 函数中进行验证:
使用 WinDBG 调试内核驱动
既然验证代码位于内核中,需要使用 WinDBG 对驱动进行调试。
在 WinDBG 中使用 lm 命令查看所有已加载的模块,可以看到 WinKer 就是程序加载的驱动。
使用 !drvobj WinKer 命令查看 WinKer 驱动的详细信息:
在输出的设备对象列表中,点击 87bc0650(也可以手动输入命令 !devobj 87bc0650)。从中可以得知驱动对象的地址为 87bc0780。有了驱动对象地址,就可以使用 dt 命令查看其数据结构。
还记得前面提到的 sub_11288 函数对应的派遣例程吗?派遣函数的地址存放在 MajorFunction 数组中,通过这个地址可以找到对应的函数进行调试。
sub_11288 对应 MajorFunction 数组的第 0xe 个元素,因此可以通过计算 87bc0780 + 0x38 + 0xe * 4 得到该内存地址的值,即该函数的内存地址为 93316288。
前面已经分析出验证代码位于 sub_11266 (00011266) 函数中,通过计算可以得知该函数在内存中的地址:93316288 - 11288 + 00011266 = 93316266。在此地址下断点即可进行调试。
需要注意的是,在编辑框输入数据后,该断点会被命中两次,说明每输入一个字符会调用两次该函数。
分析验证逻辑
通过调试发现,READ_PORT_UCHAR 函数用于读取用户输入的数据。该函数每次只读取一个字节,同时全局变量 g_var 也在发生变化。分析流程图可知,g_var 表示输入字符在字符串中的位置。
READ_PORT_UCHAR 读取第 0 到 3 位时,返回的值分别是:0xa5、0x92、0x95、0x0b
当 g_var 等于 7 时,g_var + 100 = 107,该分支不存在,进入 default 分支执行 sub_11156 函数。
同样的分析方法,READ_PORT_UCHAR 读取第 4 到 6 位时,返回的值分别是:0xb2、0x85、0xa3。此时 g_var 值变为 200。第三个 switch 的分析过程类似。
要获取正确的 key,只需将输入的字符与 READ_PORT_UCHAR 返回的字符一一对应即可。要获取 READ_PORT_UCHAR 的返回值,需要使用 WinDBG 进行调试。

