实现CE搜索字符串功能
在学习C语言编程中,遇到一个问题,就是模拟CE的搜索功能,搜索出字符串,问题见贴图,但是对于这个题没半点办法,写了半天,错误一堆,所以向大家求教,麻烦了,如果有解决,愿意以100鱼币酬谢(ps:实在编写不出,可以的话,求教代码) 有两个问题1.这些数据是什么类型?
在内存中的二进制数字?
字符串类型?
应该是第一种吧
2.你要查找名字字符串,那么这个名字字符串有什么特征?
例如名字的第一个字符是‘@’,并且以‘\0’结尾
或者名字以0xaa55开始,以数字 -1 结尾
也就是说这个字符串必须要有某些特征才能查找
例如,这段内存中存储了角色的名字和角色的自我描述,都是字符串类型,那么肯定有某种机制来标识哪一个是名字,哪一个是自我描述
例如在内存地址0x10的位置开始的4个字节存储名字字符串的偏移地址,在内存地址0x14的位置开始的4个字节存储自我描述字符串的偏移地址
另一种情况
试想一下,一个程序在数据段保存了一个名字字符串,在代码段的某个位置进行如下引用
push 0x1380
push 0x4540
call SetName
第一条指令把那个在数据段中的字符串的地址压栈,第二条指令压入新字符串的地址,第三条指令调用一个函数,用来把数据段中的那个名字字符串修改成第2个参数指向的字符串
也就是说,你必须找到那个名字字符串在原来的那个程序中是如何引用的,这样你才能找到这个字符串
CE其实并不知道哪一个是名字字符串,CE会把所有字符串都列出来,然后一步一步过滤,例如你在哪个程序中看到名字是“abcd”,那么你在CE中搜索“abcd”,等哪个名字字符串变成“1234”时,你又继续进行搜索“1234”,这样CE的列表框中就出现了这个字符串的地址和这个字符串
如果你是通过CE找到的这个字符串,那么你可以用CE找到这个字符串的指针,然后直接在你的程序中打开那个包含名字字符串的程序,用这个指针进行访问就可以了
本帖最后由 A小小鸟 于 2019-2-14 17:49 编辑
人造人 发表于 2019-2-14 16:32
有两个问题
1.这些数据是什么类型?
在内存中的二进制数字?
这些数据是内存中的显示,从而而查找“”WOW“”字符串,以"\0"作为结尾的,我自己写出strcmp的函数实现,但是不知道如何应用到这个函数中去,其实说白了,就是C语言实现在内存中遍历字符串然后找出相对应字符串的功能,但是这个实现,我不知道用指针怎么写,这个只是模拟CE在内存查找字符串而已,就相当于自己用C语言写一个简单的函数用来在内存中在一堆字符串数据中找出"WOW"的字符串一样,求大佬指点一下吧啊{:5_91:} 跟查找字符串原理是一样的。只要知道要查找的内存地址,传入,然后对比即可。
如:
#include <stdio.h>
#include <string.h>
char *FindRoleNameAddr(char *pData, char *pRoleName);
char *FindRoleNameAddr(char *pData, char *pRoleName)
{
char temp={'\0'}; // 通过sizeof获取传入字符串的大小,定义个临时数组
char *cpData;
int i;
cpData = pData; // 先用cpData指向pData的首地址
while(1)
{
for(i=0; i<(sizeof(pRoleName)-1); i++) // 获取字符串保存到temp数组中
{
temp = *pData;
pData++;
}
if ( strcmp(temp, pRoleName)==0 ) // 对比获取到的字符串是否和目标字符串相等
{
return cpData; // 相等返回字符串所在地址
}
pData = ++cpData; // 把pData指向下一个字符的地址。
}
}
int main()
{
char *myStr = "abcdawewowfasdfsdf";
char *tStr = "wow";
char *pStr;
pStr = FindRoleNameAddr(myStr,tStr);
printf("找到:%s, 地址是:%p\n", pStr, pStr);
return 0;
}
本帖最后由 人造人 于 2019-2-14 20:34 编辑
先贴出代码
ProcessOperation.hpp
#ifndef _PROCESS_OPERATION_HPP_
#define _PROCESS_OPERATION_HPP_
#include <string>
#include <windows.h>
HANDLE GetProcessHandle(std::string ProcessName);
void CloseProcessHandle(HANDLE hProcess);
UINT32 ReadAddress_4Byte(HANDLE hProcess, UINT32 BaseAddress);
void WriteAddress_4Byte(HANDLE hProcess, UINT32 BaseAddress, UINT32 data);
#endif
ProcessOperation.cpp
#include "ProcessOperation.hpp"
#include <tlhelp32.h>
static DWORD GetProcessIdByName(std::string ProcessName)
{
DWORD dwProcessId = 0;
PROCESSENTRY32 pe32;
HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
pe32.dwSize = sizeof(PROCESSENTRY32);
Process32First(hProcessSnap, &pe32);
do
{
if(ProcessName == pe32.szExeFile)
{
dwProcessId = pe32.th32ProcessID;
break;
}
}
while(Process32Next(hProcessSnap, &pe32));
CloseHandle(hProcessSnap);
return dwProcessId;
}
HANDLE GetProcessHandle(std::string ProcessName)
{
DWORD dwProcessId = GetProcessIdByName(ProcessName);
if(dwProcessId == 0)
return nullptr;
return OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, 0, dwProcessId);
}
void CloseProcessHandle(HANDLE hProcess)
{
CloseHandle(hProcess);
}
UINT32 ReadAddress_4Byte(HANDLE hProcess, UINT32 BaseAddress)
{
UINT32 data;
SIZE_T NumberOfBytesRead;
ReadProcessMemory(hProcess, (LPCVOID)BaseAddress, &data, 4, &NumberOfBytesRead);
return data;
}
void WriteAddress_4Byte(HANDLE hProcess, UINT32 BaseAddress, UINT32 data)
{
SIZE_T NumberOfBytesWritten;
WriteProcessMemory(hProcess, (LPVOID)BaseAddress, &data, 4, &NumberOfBytesWritten);
}
main.cpp
#include "ProcessOperation.hpp"
#include <iostream>
#include <string>
char *SearchString(HANDLE hProcess, DWORD begin_address, DWORD end_address, std::string string)
{
auto iter = string.begin();
char *result = (char *)begin_address;
for(UINT32 i = 0; begin_address + i < end_address; ++i)
{
char buf;
*(UINT32 *)&buf = ReadAddress_4Byte(hProcess, begin_address + i);
if(iter == string.end())
break;
if(*iter == buf)
{
++iter;
}
else
{
iter = string.begin();
result = (char *)(begin_address + i + 1);
}
}
if(iter == string.end())
return result;
return nullptr;
}
int main()
{
HANDLE hProcess = GetProcessHandle("C.exe");
std::cout << (int *)SearchString(hProcess, 0xbb7000, 0xbba000, "hello world!") << std::endl;
CloseProcessHandle(hProcess);
return 0;
}
00BB7CF8
请按任意键继续. . .
C.exe
#include <stdio.h>
int main(void)
{
getchar();
printf("%s\n", "hello world!");
return 0;
}
程序打开C.exe这个进程,在这个进程中搜索字符串“hello world!”
std::cout << (int *)SearchString(hProcess, 0xbb7000, 0xbba000, "hello world!") << std::endl;
我们没有必要搜索0x00000000~0xFFFFFFFF,这全部的4GB内存,可以通过分析PE结构得到当前字符串可能在哪些段
例如当前程序(C.exe)中的“hello world!”,这个字符串在.rdata段
可以看到“hello world!”字符串在C.exe文件中的偏移是0x64f8
0x64f8位于.rdata段
.rdata段从文件中偏移为0x5800的位置开始
0x64f8 - 0x5800 = 0xcf8
0xcf8就是“hello world!”字符串在C.exe文件中,在.rdata段的偏移
这是在文件中的偏移
运行后.rdata段从0x17000开始,这也是一个偏移,是从ImageBase开始的偏移
从图中可以看到,ImageBase是0x400000
0x400000 + 0x17000 = 0x417000
0x417000是运行后.rdata段的虚拟地址,在文件中“hello world!”字符串在.rdata段的偏移是0xcf8,运行后在.rdata段的偏移也是0xcf8
0x417000 + 0xcf8 = 0x417cf8
0x417cf8这是“hello world”字符串在内存中的地址,在C.exe进程中的虚拟地址
但是看SearchString.exe的输出
00BB7CF8
请按任意键继续. . .
为什么是00BB7CF8,还有
std::cout << (int *)SearchString(hProcess, 0xbb7000, 0xbba000, "hello world!") << std::endl;
0xbb7000和0xbba000是怎么回事?
前面说ImageBase是0x400000,但是这是一个建议的地址,操作系统可以不使用这个地址
在我的系统上就没有使用这个地址
用CE找到的“hello world!”字符串在地址00BB7CF8
用这个地址反向计算出实际加载的ImageBase
bb7cf8 - cf8 = bb7000
bb7000 - 17000 = ba0000
ba0000就是实际使用的ImageBase
那么
ba0000 + 17000 + cf8 = bb7cf8
0xbb7cf8就是“hello world”字符串在内存中的地址,在C.exe进程中的虚拟地址
SearchString.exe输出的也是这个地址
0xbb7000是在内存中.rdata段的开始
0xbba000是在内存中.rdata段的结束
我们只搜索.rdata段
有些编译器会把只读的数据放在代码段(.text段),这时我们就需要搜索.text段
还有一些其他数据可能在其他段,我们可以分析PE结构来搜索一切可能的段
有一点我目前还不明白,通过malloc申请的内存在哪个段?
我认为可以通过分析某些数据结构得到这个段的开始地址和结束地址
这依然没有必要搜索全部的4GB内存
还有最后一个问题
之前我们的ImageBase是通过CE找到的,我们如何在我们的程序中直接添加这个功能?直接在我们的程序中计算.rdata段的开始地址和结束地址?
这个问题交给你了,如果你有兴趣的话
我目前还没有好的方法
^_^
还有一点忘了说
SearchString函数的搜索效率不高,你也许有必要改进这个函数
本帖最后由 A小小鸟 于 2019-2-15 17:58 编辑
人造人 发表于 2019-2-14 20:20
还有一点忘了说
SearchString函数的搜索效率不高,你也许有必要改进这个函数
谢谢你了啊,你辛苦了,本来想直接给100鱼币,但是却无法给,只能求助小甲鱼了 ba21 发表于 2019-2-14 18:39
跟查找字符串原理是一样的。只要知道要查找的内存地址,传入,然后对比即可。
如:
非常的感谢你,你辛苦了,也想给你100鱼币表示感谢,但是却给不了,只能求助小甲鱼帮帮忙了 A小小鸟 发表于 2019-2-15 17:59
非常的感谢你,你辛苦了,也想给你100鱼币表示感谢,但是却给不了,只能求助小甲鱼帮帮忙了
没关系,等你求回,确定是这样,再给也不迟;别浪费哥表情。要是给不起也没关系 本帖最后由 A小小鸟 于 2019-2-15 19:48 编辑
ba21 发表于 2019-2-15 18:55
没关系,等你求回,确定是这样,再给也不迟;别浪费哥表情。要是给不起也没关系
不是的,系统的评分限制鱼币数量,我说到的话绝对做到的,毕竟你认认真真的给我帮忙,我怎么能随意的辜负你的热情,我就已经在投诉建议中发了帖子了,坐等小甲鱼回复的,抱歉了啊, A小小鸟 发表于 2019-2-15 19:44
不是的,系统的评分限制鱼币数量,我说到的话绝对做到的,毕竟你认认真真的给我帮忙,我怎么能随意的辜 ...
坐等消息 ba21 发表于 2019-2-15 22:19
坐等消息
对不起,我发了帖子询问了小甲鱼,小甲鱼告诉我,没有这个功能,对不起啊,这是我的错 人造人 发表于 2019-2-14 20:20
还有一点忘了说
SearchString函数的搜索效率不高,你也许有必要改进这个函数
对不起,我发了帖子询问了小甲鱼,小甲鱼告诉我,没有这个功能,对不起啊,这是我的错 A小小鸟 发表于 2019-2-19 12:27
对不起,我发了帖子询问了小甲鱼,小甲鱼告诉我,没有这个功能,对不起啊,这是我的错
没事
^_^
页:
[1]