直接进入正题,本文使用c语言对一款小软件实现内存补丁,今天下午才自学过,便想在博客中记录下来,分析过程仅供初学者学习,大神可以绕过。

大概思路为: 1、枚举进程获得系统进程列表

2、遍历进程列表,根据进程名得到进程的PID

3、根据PID获取进程句柄

4、根据进程句柄读写内存操作

先介绍要用到的几个API函数:

一、CreateToolhelp32Snapshot

该函数用于获取进程信息或模块信息快照,函数的原型如下:

HANDLE WINAPI CreateToolhelp32Snapshot(_In_ DWORD dwFlags, //指定快照中返回的对象,为TH32CS_SNAPPROCESS表示系统中的所有进程_In_ DWORD th32ProcessID  //进程PID,用于指定进程,当为0时表示获取系统所有进程
);

函数成功返回快照句柄,失败返回INVALID_HANDLE_VALUE。

二、Process32First与Process32Next

这两个函数都是从指定的进程快照句柄中获取一个进程,从名字就可以看出Process32First用于获取第一个进程,后面的函数用于获取下一个进程,第一个函数的原型如下:

BOOL WINAPI Process32First(_In_    HANDLE           hSnapshot,   //快照句柄_Inout_ LPPROCESSENTRY32 lppe         //LPPROCESSENTRY32进程结构体
);

函数成功返回true,并将一个进程信息存储到第二个参数中,失败返回false,后面的函数参数一样。

三、OpenProcess

该函数用户打开一个进程,可以指定打开后的权限,函数原型如下:

HANDLE WINAPI OpenProcess(_In_ DWORD dwDesiredAccess, //访问权限,PROCESS_ALL_ACCESS指定所有权限_In_ BOOL  bInheritHandle,  //是否继承句柄_In_ DWORD dwProcessId      //要打开进程的PID
);

函数成功则返回进程的句柄,失败则返回NULL。

四、ReadProcessMemory

该函数用于向指定的进程的指定地址处读取数据,数据长度自定义,函数原型如下:

BOOL WINAPI ReadProcessMemory(_In_  HANDLE  hProcess,    //进程句柄_In_  LPCVOID lpBaseAddress, //要读取的地址_Out_ LPVOID  lpBuffer,    //要读取的数据缓存区_In_  SIZE_T  nSize,       //指定读取的字节大小_Out_ SIZE_T  *lpNumberOfBytesRead  //实际读取的字节大小
);

函数失败返回0,否则读取成功。

五、WriteProcessMemory

该函数用于向指定的进程的指定地址处写数据,数据长度自定义,函数原型如下:

BOOL WINAPI WriteProcessMemory(_In_  HANDLE  hProcess,  //进程句柄_In_  LPVOID  lpBaseAddress,  //要写入的地址_In_  LPCVOID lpBuffer,     //要写入的数据缓存区_In_  SIZE_T  nSize,       //指定写入的大小 _Out_ SIZE_T  *lpNumberOfBytesWritten //实际写入的大小
);

函数失败返回0,否则写入成功。

这里还需要介绍下进程结构体 PROCESSENTRY32,该结构体的定义如下:

typedef struct tagPROCESSENTRY32 {DWORD dwSize; // 结构大小;DWORD cntUsage; // 此进程的引用计数;DWORD th32ProcessID; // 进程ID;DWORD th32DefaultHeapID; // 进程默认堆ID;DWORD th32ModuleID; // 进程模块ID;DWORD cntThreads; // 此进程开启的线程计数;DWORD th32ParentProcessID;// 父进程ID;LONG pcPriClassBase; // 线程优先权;DWORD dwFlags; // 保留;WCHAR szExeFile[MAX_PATH]; // 进程全名;
} PROCESSENTRY32;

这里我们只需要用到th32ProcessID和szExeFile这两个属性。

现在介绍我们需要打补丁的小软件,软件截图如下:

该软件是一个注册码验证,需要输入用户名和正确的序列号,输入正确时弹出正确的提示信息,否则弹出错误的提示信息,如下图:

我们现在要做的就是,不管输入是否正确,总是弹出正确的提示,用OD打开软件,输入提示字符串,定位到如下地方:

00402588   .  8945 B4       mov dword ptr ss:[ebp-0x4C],eax
0040258B      74 58         je short Afkayas.004025E5                ;  关键跳
0040258D   .  68 801B4000   push Afkayas.00401B80                    ;  You Get It
00402592   .  68 9C1B4000   push Afkayas.00401B9C                    ;  \r\n
00402597   .  FFD7          call edi                                 ;  msvbvm50.__vbaStrCat
00402599   .  8BD0          mov edx,eax
0040259B   .  8D4D E8       lea ecx,dword ptr ss:[ebp-0x18]
0040259E   .  FFD3          call ebx                                 ;  msvbvm50.__vbaStrMove
004025A0   .  50            push eax
004025A1   .  68 A81B4000   push Afkayas.00401BA8                    ;  KeyGen It Now
004025A6   .  FFD7          call edi                                 ;  msvbvm50.__vbaStrCat
004025A8   .  8D4D 94       lea ecx,dword ptr ss:[ebp-0x6C]
004025AB   .  8945 CC       mov dword ptr ss:[ebp-0x34],eax
004025AE   .  8D55 A4       lea edx,dword ptr ss:[ebp-0x5C]
004025B1   .  51            push ecx
004025B2   .  8D45 B4       lea eax,dword ptr ss:[ebp-0x4C]
004025B5   .  52            push edx
004025B6   .  50            push eax
004025B7   .  8D4D C4       lea ecx,dword ptr ss:[ebp-0x3C]
004025BA   .  6A 00         push 0x0
004025BC   .  51            push ecx
004025BD   .  C745 C4 08000>mov dword ptr ss:[ebp-0x3C],0x8
004025C4   .  FF15 10414000 call dword ptr ds:[<&MSVBVM50.#rtcMsgBox>;  正确的提示
004025CA   .  8D4D E8       lea ecx,dword ptr ss:[ebp-0x18]
004025CD   .  FF15 80414000 call dword ptr ds:[<&MSVBVM50.__vbaFreeS>;  msvbvm50.__vbaFreeStr
004025D3   .  8D55 94       lea edx,dword ptr ss:[ebp-0x6C]
004025D6   .  8D45 A4       lea eax,dword ptr ss:[ebp-0x5C]
004025D9   .  52            push edx
004025DA   .  8D4D B4       lea ecx,dword ptr ss:[ebp-0x4C]
004025DD   .  50            push eax
004025DE   .  8D55 C4       lea edx,dword ptr ss:[ebp-0x3C]
004025E1   .  51            push ecx
004025E2   .  52            push edx
004025E3   .  EB 56         jmp short Afkayas.0040263B               ;  跳过错误提示
004025E5   >  68 C81B4000   push Afkayas.00401BC8                    ;  You Get Wrong
004025EA   .  68 9C1B4000   push Afkayas.00401B9C                    ;  \r\n
004025EF   .  FFD7          call edi                                 ;  msvbvm50.__vbaStrCat
004025F1   .  8BD0          mov edx,eax
004025F3   .  8D4D E8       lea ecx,dword ptr ss:[ebp-0x18]
004025F6   .  FFD3          call ebx                                 ;  msvbvm50.__vbaStrMove
004025F8   .  50            push eax
004025F9   .  68 E81B4000   push Afkayas.00401BE8                    ;  Try Again
004025FE   .  FFD7          call edi                                 ;  msvbvm50.__vbaStrCat
00402600   .  8945 CC       mov dword ptr ss:[ebp-0x34],eax
00402603   .  8D45 94       lea eax,dword ptr ss:[ebp-0x6C]
00402606   .  8D4D A4       lea ecx,dword ptr ss:[ebp-0x5C]
00402609   .  50            push eax
0040260A   .  8D55 B4       lea edx,dword ptr ss:[ebp-0x4C]
0040260D   .  51            push ecx
0040260E   .  52            push edx
0040260F   .  8D45 C4       lea eax,dword ptr ss:[ebp-0x3C]
00402612   .  6A 00         push 0x0
00402614   .  50            push eax
00402615   .  C745 C4 08000>mov dword ptr ss:[ebp-0x3C],0x8
0040261C   .  FF15 10414000 call dword ptr ds:[<&MSVBVM50.#rtcMsgBox>;  错误的提示
00402622   .  8D4D E8       lea ecx,dword ptr ss:[ebp-0x18]

地址0040258B处的跳转跳过了正确的提示,直接到达了错误提示,如果此处不跳转,就会执行正确的提示,而且在下方的jmp可以跳过错误的提示,因此,只需要将此地址处的指令进行NOP,即写入两字节的0x90,即可以破解,源码如下:

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <tlhelp32.h>
int main()
{//首先获取进程PIDint pid=0;PROCESSENTRY32 processentry={0};   //创建一个进程结构体processentry.dwSize=sizeof(PROCESSENTRY32);HANDLE hprocessSnap=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);  //获取进程快照if(hprocessSnap==INVALID_HANDLE_VALUE){return -1;}int flag=Process32First(hprocessSnap,&processentry);  //获取第一个进程while(flag){if(lstrcmpi(processentry.szExeFile,"Afkayas.exe")==0){  //lstrcmpi函数用于比较两个字符串,相同时返回0pid=processentry.th32ProcessID;}//  printf("%d----%s\n",processentry.th32ProcessID,processentry.szExeFile);flag=Process32Next(hprocessSnap,&processentry);}CloseHandle(hprocessSnap);if(pid==0){printf("请先打开进程");return 0;}//获取进程句柄HANDLE procHandle=OpenProcess(PROCESS_ALL_ACCESS,FALSE,pid);if(procHandle==NULL){printf("打开进程失败!");return 0;}//测试读进程数据int tmp;DWORD buffer;if(ReadProcessMemory(procHandle,0x400000,&tmp,4,&buffer)){printf("读取成功,读取内容为:%#X\n",tmp);}else{printf("读取进程内容失败!");}tmp=0x9090;if(WriteProcessMemory(procHandle,0x40258B,&tmp,2,&buffer)){printf("写入进程内容成功\n");}else{printf("写入进程内容失败!\n");return 0;}system("pause");return 0;
}

打开程序后,再执行该补丁程序,提示注册成功:

本文只是记录了自己的学习过程,新手可以用来参考学习,大神发现问题欢迎指出。

C语言枚举进程,实现一个简单的内存补丁相关推荐

  1. C语言游戏脚本:一个简单的内存脚本!

    通过 C 语言编写一个简单的外挂,通过 API 函数修改游戏数据,从而实现作弊功能 ● 对象分析 ● 要用的 API 函数简单介绍 ● 编写测试效果 ● 总体评价 对象分析 本次游戏对象为 Super ...

  2. glibc版本查看_[译] 写一个简单的内存分配器(替换glibc中的malloc函数)

    本文介绍如何用c语言实现一个简单的内存分配器,可替换glibc中的 malloc(), calloc(), realloc(), free(). 这是一篇入门级别的文章,所以不会介绍所有的细节. 代码 ...

  3. 编程题目:使用C++语言模拟完成一个简单的计算机系统

    编程题目:使用C++语言模拟完成一个简单的计算机系统(举一个管理人员的例子,其他的例子与下述方法一致即可) #include<iostream.h> #include<math.h& ...

  4. c语言设计程序计算器,C语言程序设计,做一个简单计算器

    题目: C语言程序设计,做一个简单计算器 程序内容有:加减乘除和平方,立方,开方等.用if或者swith结构来编程. 算加法时只输出加法的结果,算减法时只出减法的结果,如此类推. 解答: 已发送, # ...

  5. python 消息队列 go_gmq: gmq是基于redis提供的特性,使用go语言开发的一个简单易用的消息队列;支持延迟任务,异步任务,超时任务,优先级任务...

    1. 概述 gmq是基于redis提供的特性,使用go语言开发的一个简单易用的队列;关于redis使用特性可以参考之前本人写过一篇很简陋的文章Redis 实现队列; gmq的灵感和设计是基于有赞延迟队 ...

  6. 实现自己的operator new和operator delete以及实现一个简单的内存池管理类

    为什么有必要写自己的operator new和operator delete? 为了效率.缺省的operator new和operator delete具有非常好的通用性,它的这种灵活性也使得在某些特 ...

  7. C/C++编程日记:制作一个简单的内存外挂

    简单外挂 通过 C 语言编写一个简单的外挂,通过api函数修改游戏数据,从而实现作弊功能 对象分析 要用的 API 函数简单介绍 编写测试效果 本次游戏对象为 Super Mario XP 没有更新所 ...

  8. 【Go语言】实现一个简单的纯后端学员管理系统,入门级别练手项目,练习结构体,接口,构造函数

    GO语言实现一个简单的纯后端学员管理系统 项目总览: 一.项目开发日志 二.前情知识补充 1.构造函数:用来在创建对象时初始化对象 2.方法和接收者 三.主函数中的内容 四.逐个自定义函数拆解分析 1 ...

  9. java虚拟机运行C语言_用C语言来实现一个简单的虚拟机

    必要的准备工作及注意事项: 在开始之前需要做以下工作: 一个C编译器--我使用了 clang 3.4,也可以用其它支持 c99/c11 的编译器: 文本编辑器--我建议使用基于IDE的文本编辑器,我使 ...

  10. C语言实现的一个简单的HTTP程序

    以下是参考<winsock网络编程经络>中讲解web应用http协议的时候,实现的一个简单的http程序,包含一个服务器和一个客户端. 先贴上客户端的程序:   /************ ...

最新文章

  1. 为Nginx制作404 403 500等错误页面
  2. linux VFS 虚拟文件系统 简介 super_block inode dentry file
  3. “影响100活动”答记者问(二)
  4. 【机器学习】异常检测算法之(HBOS)-Histogram-based Outlier Score
  5. 节约内存:Instagram的Redis实践(转)
  6. 前端学习(1414):ajax基础
  7. 推荐系统——协同过滤
  8. JAVA入门级教学之(char类型)
  9. (28)FPGA计数器设计(软核实现)
  10. python开发好吗_用Python开发应用好用吗?
  11. Graph——bfs,dfs
  12. 约瑟夫问题的数学解法
  13. CGAL几何库配置教程
  14. 郭依婷—大学生的创业故事
  15. 编解码学习笔记(七):微软Windows Media系列
  16. 基于JAVA EE的临床科室管理系统
  17. HTTPS TSL/SSL详解
  18. 【译】JavaScript中的Promises
  19. 14个PPT资源素材网站,再也不怕做PPT了
  20. linux 将sda分区扩容

热门文章

  1. 服务器装无线上网卡,dlink无线上网卡怎么安装和设置
  2. H.264编解码标准详解
  3. 如何使用google code(转)
  4. Linux系统下强制删除文件
  5. 智慧城市的顶层设计与底层对接
  6. Auto Tile 自动拼接地图和墙壁
  7. 传统企业如何开启O2O营销模式?
  8. 【知识总结】情感分类
  9. 梯度提升决策树GBDT
  10. python 广义线性模型_scikit-learn 1.1 广义线性模型(Generalized Linear Models)