周壑x64位内核学习(二)、x64内核32位程序的运行

实验环境:win10 1903 + wmware
实验程序:winxp sp3下的记事本程序
实验工具:windbg + x32dbg + x64dbg

一、32位程序切入64位的大致流程

ctrl + G跳转到系统API地址
0
 
0
call edx ,edx的地址是77898c50
ctrl + G跳转到那里
0
wow64Transition好像是一个宏,双击进入
0
可以看到一个跨段跳转,跳转后 cs = 0x33
这里,我们回想一下gdt表
0
根据段描述符的l标志,一般32位的程序的cs段是指向第四个段描述符的,但这里指向了第6个段描述符,也就是l位至1的段描述符(判断理由:拆分段选择子)。这之后程序将被当作64位程序来运行..
同样,这之后的指令也会被当作64位来处理!!
 

二、windbg调试x32错误分析代码

 
由于x32dbg只能分析32位的指令,所以x32dbg将会把之后的指令分析错误,x64dbg也不能调试32位程序,我们可以使用windbg进行调试
 
0
.process /i 中 /i命令功能: 以侵入性地检查进程状态
 
0
 
0
 
0
 
我们可以发现,在ntdll.dll中不但存在32位代码,也存在64位代码
那么我们写的程序也可以通过跨段跳转的方式实现同时包含32位与64位代码
 

三、跨段实现兼容32位与64位代码

#include <stdio.h> #include <windows.h> #include <stdlib.h> char far_jmp[10] = {0x00, 0x70, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00};//00417000// 00417000 : 0x23 // char secret[9] = {0}; //00417148// void __declspec(naked) Fun_read() { __asm { __emit 0x90 __emit 0x4c //mov qword ptr ds :[0x417148],r12//将r12寄存器中的数据取出放到sercet数组的位置// mov qword ptr ds:[0x0000000000417148], r12//直接 4C 89 24 25 48 71 41 00 __emit 0x89 __emit 0x24 __emit 0x25 __emit 0x48 __emit 0x71 __emit 0x41 __emit 0x00 __emit 0xb8 //mov eax,far_jmp(00417000)// 借助far_jmp跳回去// __emit 0x00 __emit 0x70 __emit 0x41 __emit 0x00 __emit 0x48 __emit 0xff __emit 0x28 } } void __declspec(naked) Fun_write() //函数功能就是把一个数据存放到r12寄存器中 { __asm { __emit 0x49 //mov r12,0x3436206F6C6C6568// //49 BC 68 65 6C 6C 6F 20 36 34// __emit 0xbc __emit 0x68 __emit 0x65 __emit 0x6c __emit 0x6c __emit 0x6f __emit 0x20 __emit 0x36 __emit 0x34 __emit 0xb8 //mov eax,far_jmp(00417000)// __emit 0x00 __emit 0x70 __emit 0x41 __emit 0x00 __emit 0x48 //返回,jmp far tword ptr ds:[rax],48:ff28// tword 是10个字节,剩下两个字节作为段选择子/// 跨段跳转跳回32位// __emit 0xff __emit 0x28 } } int main() { printf("The address of Fun_read is: %p\n",Fun_read); //0041111d// printf("The address of Fun_write is: %p\n",Fun_write); //004111b3// printf("The address of far_jmp is: %p\n",far_jmp); //00417000// printf("The address of secret is : %p\n",secret); //00417148// //跨段跳转到Fun_write// //jmp far 33:004111b3 *(unsigned int *)far_jmp = 0x0041147F; __asm { __emit 0xea __emit 0xb3 __emit 0x11 __emit 0x41 __emit 0x00 __emit 0x33 __emit 0x00 } L1: //0x0041147F// printf("Write OK!\n"); system("pause"); *(unsigned int *)far_jmp = 0x004114BE; __asm //jmp far 33:0041111d// 跨段跳转到Fun_read// { __emit 0xea __emit 0x1d __emit 0x11 __emit 0x41 __emit 0x00 __emit 0x33 __emit 0x00 } L2: //0x004114BE printf("get data OK!\n"); printf("%s\n",secret); system("pause"); return 0; }

 

 
这是抄的周壑老师写的程序
目的就是隐藏字符串Hello 64
0
 
大致思路就是跨段跳转进64位环境,把字符串保存给r12寄存器后再跨段回来,需要的时候再跨段取出来。。
在保存的期间内,只要r12寄存器不被其他api修改,就能达到隐藏的目的

__EOF__

本文作者_TLSN
本文链接https://www.cnblogs.com/lordtianqiyi/articles/16057095.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   TLSN  阅读(573)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示