构建一个CPU模拟器
一、概述
本章节介绍的是windows环境下unicorn框架和capstone框架的使用。
二、工具
Visual stdio 2019
Cmake
Git
三、构建步骤
1、clone unicorn和capstone框架的源码。(注意clone的分支为最新版本,不是master)
git clone https://github.com/unicorn-engine/unicorn.gitgit clone https://github.com/capstone-engine/capstone.git
2、编译unicorn
(1) 使用git bash或者cmd进入unicorn目录,执行下面几条命令
mkdir buildcd buildcmake .. -G "Visual Studio 16 2019" -A "x64" -DCMAKE_BUILD_TYPE=Release
(2)接着在build目录下会生成一个unicorn.sln文件,使用visual stdio 2019打开,编译输出。在build目录下会生成unicorn.lib,在build/debug目录下会生成许多文件,只需要unicorn.dll即可。
3、编译capstone
(1)使用visual stdio 2019打开capstone/msvc目录下的capstone.sln文件,编译之后在capstone\msvc\x64\Debug目录下会生成capstone.dll和capstone.lib文件。
4、创建模拟器项目
使用visual stdio 2019创建一个新项目,然后导入上面两步骤生成的文件,再将上述框架中
capstone和unicorn头文件(在include目录下)放入工程根目录中。
5、实现代码
下面是模拟x86架构64位程序代码片段,其中test_00007FF6B9541000.bin是.text段的内存dump文件,test_00000039AB52A000.bin为.stack段内存dump,test_00007FF6B9549000.bin为.rdata段内存dump,test_00007FF6B954C000.bin为.data段内存dump,test_00007FF6B9531000.bin为.textbss段内存dump。
csh g_x64_cs_handle = NULL;
cs_insn* g_x64_cs_insn = NULL;
size_t g_x64_cs_count = 0; // how many instruction that this capstone API disassembly successfully
cs_err g_x64_cs_err = CS_ERR_OK;uc_engine* g_x64_uc = NULL;
uc_err g_x64_uc_err = UC_ERR_OK; // error number that unicorn emulate instructionDWORD64 g_x64_instruction_count = 0;REG_X86 g_x64_reg = { 0 }; // init register//#define CODE "\x55\x48\x8b\x05\xb8\x13\x00\x00"VOID x64_init_registers()
{g_x64_reg.reg.r_rax = 0x00007FF6B9541230;g_x64_reg.reg.r_rcx = 0x00000039AB77F000;g_x64_reg.reg.r_rdx = 0x00007FF6B9541230;g_x64_reg.reg.r_rbx = 0x0000000000000000;g_x64_reg.reg.r_rsp = 0x00000039AB52FDB8;g_x64_reg.reg.r_rbp = 0x0000000000000000l;g_x64_reg.reg.r_rsi = 0x0000000000000000;g_x64_reg.reg.r_rdi = 0x0000000000000000;g_x64_reg.reg.r_rip = 0x00007FF6B9542330;g_x64_reg.reg.r_rflag = 0x0000000000000246;g_x64_reg.reg.r_r8 = 0x00000039AB77F000;g_x64_reg.reg.r_r9 = 0x00007FF6B9541230;g_x64_reg.reg.r_r10 = 0x00007FFFBD807C90;g_x64_reg.reg.r_r11 = 0x0000000000000000l;g_x64_reg.reg.r_r12 = 0x0000000000000000l;g_x64_reg.reg.r_r13 = 0x0000000000000000l;g_x64_reg.reg.r_r14 = 0x0000000000000000l;g_x64_reg.reg.r_r15 = 0x0000000000000000l;}x64_FileInformation fileinfo[] =
{// BaseAddress FileSize Path allocate buffer address(PVOID)0x00007FF6B9541000 , 0x8000 , L".\\x64_binary\\test_00007FF6B9541000.bin" , NULL , //.text(PVOID)0x00000039AB52A000 , 0x6000 , L".\\x64_binary\\test_00000039AB52A000.bin" , NULL , //.stack(PVOID)0x00007FF6B9549000 , 0x3000 , L".\\x64_binary\\test_00007FF6B9549000.bin" , NULL , //.rdata(PVOID)0x00007FF6B954C000 , 0x1000 , L".\\x64_binary\\test_00007FF6B954C000.bin" , NULL , //.data(PVOID)0x00007FF6B9531000 , 0x10000 , L".\\x64_binary\\test_00007FF6B9531000.bin" , NULL , //.textbss};VOID x64_emulate()
{g_x64_cs_err = cs_open(CS_ARCH_X86, CS_MODE_64, &g_x64_cs_handle);g_x64_uc_err = uc_open(UC_ARCH_X86, UC_MODE_64, &g_x64_uc);if (g_x64_cs_err || g_x64_uc_err){printf("ERROR: Failed to initialize engine!\n");return;}cs_option(g_x64_cs_handle, CS_OPT_DETAIL, CS_OPT_ON);for (ULONG i = 0; i < sizeof(fileinfo) / sizeof(fileinfo[0]); i++){FILE* pFile = NULL;fileinfo[i].buffer = (PVOID)malloc(fileinfo[i].FileSize);if (!fileinfo[i].buffer){printf("Allocate mem fail!\n");return;}pFile = _wfopen(fileinfo[i].FileName, L"rb");if (!pFile){printf("open file error code : <%d>\n", GetLastError());return;}fread(fileinfo[i].buffer, fileinfo[i].FileSize, 1, pFile);if (pFile)fclose(pFile);g_x64_uc_err = uc_mem_map(g_x64_uc, (DWORD64)fileinfo[i].BaseAddress, fileinfo[i].FileSize, UC_PROT_ALL);if (g_x64_uc_err){printf("uc mem map error!Error Code:<%d>\n", g_x64_uc_err);return;}g_x64_uc_err = uc_mem_write(g_x64_uc, (DWORD64)fileinfo[i].BaseAddress, fileinfo[i].buffer, fileinfo[i].FileSize);if (g_x64_uc_err){printf("uc mem write error!Error Code:<%d>\n", g_x64_uc_err);return;}}x64_init_registers();x64_write_uc_registers();BYTE Code[32] = { 0 };do{uc_mem_read(g_x64_uc, g_x64_reg.reg.r_rip, Code, sizeof(Code));g_x64_cs_count = cs_disasm(g_x64_cs_handle, Code, sizeof(Code), g_x64_reg.reg.r_rip, 1, &g_x64_cs_insn);if (!g_x64_cs_count)break;g_x64_uc_err = uc_emu_start(g_x64_uc, g_x64_reg.reg.r_rip, 0xffffffffffffffff, 0, 1);x64_read_uc_registers();x64_print_uc_registers();x64_print_uc_stack(g_x64_reg.reg.r_rsp);cs_free(g_x64_cs_insn, 1);if (g_x64_uc_err){printf("uc_emu_start error!Error Code:<%d>\n", g_x64_uc_err);break;}g_x64_instruction_count++;} while (g_x64_cs_count);cs_close(&g_x64_cs_handle);uc_close(g_x64_uc);}VOID x64_read_uc_registers()
{uc_reg_read(g_x64_uc, UC_X86_REG_RAX, &g_x64_reg.reg.r_rax);uc_reg_read(g_x64_uc, UC_X86_REG_RCX, &g_x64_reg.reg.r_rcx);uc_reg_read(g_x64_uc, UC_X86_REG_RDX, &g_x64_reg.reg.r_rdx);uc_reg_read(g_x64_uc, UC_X86_REG_RBX, &g_x64_reg.reg.r_rbx);uc_reg_read(g_x64_uc, UC_X86_REG_RSP, &g_x64_reg.reg.r_rsp);uc_reg_read(g_x64_uc, UC_X86_REG_RBP, &g_x64_reg.reg.r_rbp);uc_reg_read(g_x64_uc, UC_X86_REG_RSI, &g_x64_reg.reg.r_rsi);uc_reg_read(g_x64_uc, UC_X86_REG_RDI, &g_x64_reg.reg.r_rdi);uc_reg_read(g_x64_uc, UC_X86_REG_RIP, &g_x64_reg.reg.r_rip);uc_reg_read(g_x64_uc, UC_X86_REG_RFLAGS, &g_x64_reg.reg.r_rflag);uc_reg_read(g_x64_uc, UC_X86_REG_R8, &g_x64_reg.reg.r_r8);uc_reg_read(g_x64_uc, UC_X86_REG_R9, &g_x64_reg.reg.r_r9);uc_reg_read(g_x64_uc, UC_X86_REG_R10, &g_x64_reg.reg.r_r10);uc_reg_read(g_x64_uc, UC_X86_REG_R11, &g_x64_reg.reg.r_r11);uc_reg_read(g_x64_uc, UC_X86_REG_R12, &g_x64_reg.reg.r_r12);uc_reg_read(g_x64_uc, UC_X86_REG_R13, &g_x64_reg.reg.r_r13);uc_reg_read(g_x64_uc, UC_X86_REG_R14, &g_x64_reg.reg.r_r14);uc_reg_read(g_x64_uc, UC_X86_REG_R15, &g_x64_reg.reg.r_r15);}VOID x64_write_uc_registers()
{uc_reg_write(g_x64_uc, UC_X86_REG_RAX, &g_x64_reg.reg.r_rax);uc_reg_write(g_x64_uc, UC_X86_REG_RCX, &g_x64_reg.reg.r_rcx);uc_reg_write(g_x64_uc, UC_X86_REG_RDX, &g_x64_reg.reg.r_rdx);uc_reg_write(g_x64_uc, UC_X86_REG_RBX, &g_x64_reg.reg.r_rbx);uc_reg_write(g_x64_uc, UC_X86_REG_RSP, &g_x64_reg.reg.r_rsp);uc_reg_write(g_x64_uc, UC_X86_REG_RBP, &g_x64_reg.reg.r_rbp);uc_reg_write(g_x64_uc, UC_X86_REG_RSI, &g_x64_reg.reg.r_rsi);uc_reg_write(g_x64_uc, UC_X86_REG_RDI, &g_x64_reg.reg.r_rdi);uc_reg_write(g_x64_uc, UC_X86_REG_RIP, &g_x64_reg.reg.r_rip);uc_reg_write(g_x64_uc, UC_X86_REG_RFLAGS, &g_x64_reg.reg.r_rflag);uc_reg_write(g_x64_uc, UC_X86_REG_R8, &g_x64_reg.reg.r_r8);uc_reg_write(g_x64_uc, UC_X86_REG_R9, &g_x64_reg.reg.r_r9);uc_reg_write(g_x64_uc, UC_X86_REG_R10, &g_x64_reg.reg.r_r10);uc_reg_write(g_x64_uc, UC_X86_REG_R11, &g_x64_reg.reg.r_r11);uc_reg_write(g_x64_uc, UC_X86_REG_R12, &g_x64_reg.reg.r_r12);uc_reg_write(g_x64_uc, UC_X86_REG_R13, &g_x64_reg.reg.r_r13);uc_reg_write(g_x64_uc, UC_X86_REG_R14, &g_x64_reg.reg.r_r14);uc_reg_write(g_x64_uc, UC_X86_REG_R15, &g_x64_reg.reg.r_r15);}VOID x64_print_uc_registers()
{printf("\n>--- --- --- %lld --- --- ---<\n", g_x64_instruction_count);printf("%#16llx:\t%s\t%s\n",g_x64_cs_insn[0].address,g_x64_cs_insn[0].mnemonic,g_x64_cs_insn[0].op_str);printf("rax=0x%16llx\n", g_x64_reg.reg.r_rax);printf("rcx=0x%16llx\n", g_x64_reg.reg.r_rcx);printf("rdx=0x%16llx\n", g_x64_reg.reg.r_rdx);printf("rbx=0x%16llx\n", g_x64_reg.reg.r_rbx);printf("rsp=0x%16llx\n", g_x64_reg.reg.r_rsp);printf("rbp=0x%16llx\n", g_x64_reg.reg.r_rbp);printf("rsi=0x%16llx\n", g_x64_reg.reg.r_rsi);printf("rdi=0x%16llx\n", g_x64_reg.reg.r_rdi);printf("rip=0x%16llx\n", g_x64_reg.reg.r_rip);printf("rfl=0x%16llx\n", g_x64_reg.reg.r_rflag);printf("r8 =0x%16llx\n", g_x64_reg.reg.r_r8);printf("r9 =0x%16llx\n", g_x64_reg.reg.r_r9);printf("r10=0x%16llx\n", g_x64_reg.reg.r_r10);printf("r11=0x%16llx\n", g_x64_reg.reg.r_r11);printf("r12=0x%16llx\n", g_x64_reg.reg.r_r12);printf("r13=0x%16llx\n", g_x64_reg.reg.r_r13);printf("r14=0x%16llx\n", g_x64_reg.reg.r_r14);printf("r15=0x%16llx\n", g_x64_reg.reg.r_r15);}VOID x64_print_uc_stack(DWORD64 rsp)
{DWORD64 val = 0;for (ULONG i = 5; i > 0; i--){uc_mem_read(g_x64_uc, (DWORD64)(rsp - i * 8), &val, sizeof(DWORD64));printf("\t|%16llx|\n", val);}uc_mem_read(g_x64_uc, (DWORD64)rsp, &val, sizeof(DWORD64));printf("===> |%16llx|\n", val);for (ULONG i = 1; i < 5; i++){uc_mem_read(g_x64_uc, (DWORD64)(rsp + i * 8), &val, sizeof(DWORD64));printf("\t|%16llx|\n", val);}
}
上述代码是模拟x86_64程序,这个cpu模拟器框架还支持arm,aarch64,mips,risc-v
risc-v 64等汇编模拟。后续还会给出模拟risc-v 64程序的步骤。
学习过程中还有很多不足,还望朋友们指正!
构建一个CPU模拟器相关推荐
- AI:2023年6月9日北京智源大会演讲分享之基础模型前沿技术论坛—《工程化打造AI中的CPU》、《构建一个AI系统:在LLM上应用带有RLHF来推进定制》、《多模态预训练的进展回顾与展望》、《扩展大
AI:2023年6月9日北京智源大会演讲分享之基础模型前沿技术论坛-<工程化打造AI中的CPU>.<构建一个AI系统:在LLM上应用带有RLHF来推进定制>.<多模态预训 ...
- 基于五阶段流水线的RISC-V CPU模拟器实现
RISC-V是源自Berkeley的开源体系结构和指令集标准.这个模拟器实现的是RISC-V Specification 2.2中所规定RV64I指令集,基于标准的五阶段流水线,并且实现了分支预测模块 ...
- 基于PyTorch,如何构建一个简单的神经网络
本文为 PyTorch 官方教程中:如何构建神经网络.基于 PyTorch 专门构建神经网络的子模块 torch.nn 构建一个简单的神经网络. 完整教程运行 codelab→ https://ope ...
- 从零构建一个简单的 Python 框架
为什么你想要自己构建一个 web 框架呢?我想,原因有以下几点: 你有一个新奇的想法,觉得将会取代其他的框架 你想要获得一些名气 你遇到的问题很独特,以至于现有的框架不太合适 你对 web 框架是如何 ...
- 构建一个分布式操作系统的简单方案—答陈硕的“分布式系统中的进程标识”一文...
对分布式系统中的进程标识"一文的疑问 刚才看到陈硕先生的一篇blog:"分布式系统中的进程标识",地址:http://www.cnblogs.com/Solstice/a ...
- 转载:谢谢原作者:块设备驱动实战基础篇一 (170行代码构建一个逻辑块设备驱动)
1 内核块设备驱动基础学习与实战 1.1 设备驱动IO架构初探 操作系统是如何将数据读到缓冲区的,发生了什么?我们带着这样的问题,粗略走一下read调用系统过程,希望这个初探,可以唤起大家研究操作 ...
- pip install pygame_使用 Python 和 Pygame 模块构建一个游戏框架!
这系列的第一篇通过创建一个简单的骰子游戏来探究 Python.现在是来从零制作你自己的游戏的时间. 在我的这系列的第一篇文章 中, 我已经讲解如何使用 Python 创建一个简单的.基于文本的骰子游戏 ...
- pygame为游戏添加背景_万能的Python和Pygame模块构建一个游戏框架
通过创建一个简单的骰子游戏来探究 Python.现在是来从零制作你自己的游戏的时间. 在我的这系列的第一篇文章中, 我已经讲解如何使用 Python 创建一个简单的.基于文本的骰子游戏.这次,我将展示 ...
- python pygame模块怎么写游戏_使用 Python 和 Pygame 模块构建一个游戏框架
这系列的第一篇通过创建一个简单的骰子游戏来探究 Python.现在是来从零制作你自己的游戏的时间. 在我的这系列的第一篇文章 中, 我已经讲解如何使用 Python 创建一个简单的.基于文本的骰子游戏 ...
最新文章
- POJ 2516 Minimum Cost 最小费用流
- spring_通过Spring Boot了解H2 InMemory数据库
- 江苏省计算机学会科学技术奖,孙国梓
- Codeforces Round #632 (Div. 2) E. Road to 1600 构造好题
- centOs 7.2*64 ECS nginx安装教程
- 基于JAVA+SpringBoot+Mybatis+MYSQL的在线购物商城系统
- 【翻译】五步快速使用LINQPad尝鲜StreamInsight
- git 查看修改明细_git查看某个文件的修改历史
- eclipse插件:OpenExplorer快速打开文件目录
- Word 利用 VBA 批量设置图片格式
- SD内存卡格式化后如何数据恢复教程
- 如何选购计算机的硬盘,教你如何选配电脑—硬盘篇
- 【科大讯飞Face】
- 2014年全国专业技术人员计算机应用能力考试大纲,2014年全国专业技术人员计算机应用能力考试 Excel2003...
- nginx+uwsgi+django1.9+mysql+python2.7部署到CentOS6.5
- 数据库实体间关联关系:一对一、一对多、多对多
- 屏幕录像机(bb flashback pro 4)pjb v4.1.21
- 存储卡 android文件夹,安卓系统下SD卡文件夹功能介绍
- web网站的注销功能实现
- 应用“真心话大冒险”项目总结
热门文章
- Python Console报错:Cannot start process, the working directory does not exist
- 斗鱼上市,腾讯坐“快”观“虎斗”
- Android错误之(Android 6.0)Unable to add window android.view.ViewRootImpl$W@d4521e8 -- permission denied
- 数据中台:FastData云原生数据智能平台
- 四级英语——段落匹配(20分钟)
- linux重置定时关机,Linux 定时关机与重新启动
- java corba实例,OpenORB开发CORBA的实例介绍
- Excel如何隔列填充字体颜色
- Android UCV 同时打开多路摄像头
- C语言switch中break的作用,C语言switch中break语句的作用