my cheat engine needs searching speed!!!

Hi all! I've made a simple cheat engine (it works! I tested it extensively with the winged warrior rpg :D ) and I need some help to improve it... It can be attached to a running process, search for some given value of given size (after searching for the first time, if u don't select new search, the next search will only be done on the results of the previous search), store the address of that value and create patches that modify the process memory. A patch consists of a description (so u know what it does), the address it is performed on, the patch operation (u can add or assign a value), the value you want to add/assign, the value-type (is it a constant or is it the value of another address?) and the patch-type (static if the value is asked upon creating the patch and doesn't change, dynamic if the value is asked every time you apply the patch). You can also save and load the address and patch tables. My problem is that the search function is very slow... for example it needs more than 10 seconds to search an area that the official Cheat Engine searches in less than a second... :/ How do I fix that?? I suspect that the official Cheat Engine doesn't check all memory slots, there is an option where u can view the process memory and it shows it classified to categories like protection status (read, write, no access, read+write...), type (private, mapped, image), state(free, commit, reserve) and others. I suspect that it doesn't check memory slots that have "no access" in their protection status for example. But what are all these classifications? And what is the API that will enable me to interact with them??? Can anyone help? Oh, I've also made a multithreaded-search version but it only reduces the searching time to a 75-80% of the initial time, nowhere near the official Cheat Engine... Thnx in advance! Here is my code (I post the code in three parts coz it's too long to fit in one post... Just copy part A from here, parts B and C from the replies below and paste them in your compiler in that order):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
#include <fstream>
#include <iostream>
#include <windows.h>
#include <vector>

using namespace std;

const char * str_table_patch_type[2]=
{
	"static","dynamic"
};
const char * str_table_value_type[2]=
{
	"constant","address"
};
const char * str_table_operation[2]=
{
	"assignment","addition"
};

struct Address
{
	char label[80];
	int address;
};

struct Patch
{
	char description[80];
	int address;
	int value;
	int size;
	
	
	int operation; //0->set, 1->add
	int value_type; //0->value, 1->address
	int patch_type; //0->static, 1->dynamic
	
};

vector<Address> address_table;
vector<Patch> patch_table;

HWND whandle; //window handle
HANDLE phandle; //process handle
DWORD pid; //process id

bool new_search=true;
vector<int> search_results[2];
int cur_result=0;
int prev_result=1;
unsigned long add_start;
unsigned long add_end;
int val;
int val_size;

bool is_attached=false;
char window_name[80];

void attach();
void attach_update();
void search();
void create_patch();
void apply_patch();
void create_label(bool use_add, int add=0);
void view_patch_table();
void view_address_table();
void save();
void load();

bool get_int(int & integer);
void get_address(int & add);

int main()
{
	
	
	//these few lines of code, give my application the "debug" privilege
	//which will allow it to obtain ANY process handle and do with
	//it ANYTHING I want it to do :D
	
	HANDLE my_process;
	HWND my_window;
	DWORD my_id;
	HANDLE htoken;
	TOKEN_PRIVILEGES tp;
	LUID luid;
	
	my_id=GetCurrentProcessId();
	my_process=OpenProcess(PROCESS_ALL_ACCESS,0,my_id);
	OpenProcessToken(my_process,TOKEN_ALL_ACCESS,&htoken);
	
	LookupPrivilegeValue(NULL,"SeDebugPrivilege", &luid );
	
	tp.PrivilegeCount = 1;
	tp.Privileges[0].Luid = luid;
	tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
	
	AdjustTokenPrivileges(htoken,FALSE,&tp,sizeof(TOKEN_PRIVILEGES),0,0);
	
	//ok, now our application has the "debug" privilege which grants
	//it absolute dominance over ANY other application :D
	
	int choice;
	while (true)
	{
		system("cls");
		cout << "What will it be?" << endl;
		cout << "(1) Attach to a process" << endl;
		cout << "(2) Search for a value" << endl;
		cout << "(3) Create a label for an address" << endl;
		cout << "(4) Create a patch" << endl;
		cout << "(5) Apply a patch" << endl;
		cout << "(6) View patch table" << endl;
		cout << "(7) View address table" << endl;
		cout << "(8) Save tables" << endl;
		cout << "(9) Load tables" << endl;
		cout << "(0) Quit" << endl;
		
		if (!get_int(choice)) continue;
		if (choice<0 || choice>9) continue;
		if (choice==0) 
		{
			cout << "kk dude, bb!" << endl; system("pause");
                        return 0;
		}
		
		system("cls");
		switch (choice)
		{
			case 1: attach();
			break;
			case 2: search();
			break;
			case 3: create_label(false);
			system("pause");
			break;
			case 4: create_patch();
			break;
			case 5: apply_patch();
			break;
			case 6: view_patch_table();
			break;
			case 7: view_address_table();
			break;
			case 8: save();
			break;
			case 9: load();
			break;
		}
	}
	
	return 0;
}

void attach_update()
{
	if (!is_attached) return;
	if (FindWindow(NULL,window_name)==0) is_attached=false;
}

bool get_int(int & integer)
{
	bool ok=true;
	
	cin >> integer;
	if (!cin) 
	{
		cin.clear(); ok=false;
	}
	while (cin.get()!='\n');
	
	return ok;
}

void get_address(int & add)
{
	int ans=0;
	int add_table_size=address_table.size();
	if (add_table_size!=0)
	{
		cout << "enter address label? (0->no, 1->yes) ";
		while (!get_int(ans)) 
                cout << "enter address label? (0->no, 1->yes) ";
	}
	
	if (ans==0)
	{
		cout << "enter address (hex): ";
		cin >> hex;
		while (!get_int(add)) cout << "enter address (hex): ";
		cin >> dec;
	}
	else
	{
		int i;
		int choice;
		for (i=0; i<add_table_size; i++)
		{
			cout << "(" << i+1 << ") " << address_table[i].label 
                             << endl;
			if (i%10==9) system("pause");
		}
		cout << "which address then? ";
		while (! (get_int(choice) &&(choice>=1)
		&& (choice<=add_table_size) ) ) cout << "which address then? ";
		add=address_table[choice-1].address;
	}
}

void create_label(bool use_add, int add)
{
	if (!use_add)
	{
		cout << "enter address (hex) :"<< endl;
		cin >>hex;
		while (!get_int(add)) cout << "enter address (hex) :"<< endl;
		cin >>dec;
	}
	
	Address new_address;
	new_address.address=add;
	cout << "enter label: ";
	cin.getline(new_address.label,80,'\n');
	
	address_table.push_back(new_address);
	cout << "new label succesfully created!"<< endl;
	
}

void attach()
{
	bool ok=true;
	is_attached=false;
	whandle=0;
	phandle=0;
	
	char name[80];
	
	cout << "Enter window name:" << endl;
	cin.getline(name,80,'\n');
	
	whandle = FindWindow(NULL,name);
	if (whandle != 0)
	{
		cout << "got window handle!"<<endl;
                GetWindowThreadProcessId(whandle,&pid);
	}
	else
	{
		cout<<"couldn't find window..."<<endl;
		ok=false;
	}
	
	
	
	if (whandle!=0) phandle = OpenProcess(PROCESS_ALL_ACCESS,0,pid);
	if (phandle != 0)
	{
		cout << "got process handle!" << endl;
	}
	else
	{
		cout << "unable to access process..." << endl;
		ok=false;
	}
	
	system("pause");
	if (!ok) return;
	
	is_attached=true;
	strcpy(window_name,name);
	return;
}
Last edited on
Code part B:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
void search()
{
	attach_update();
	if (!is_attached) 
	{
		cout << "dude, you are not attached to a process..." << endl;
                system("pause"); 
                return;
	}
	
	int ns;
	if (new_search==false)
	{
		cout << "new search? (0->no, 1->yes) ";
		while (!get_int(ns)) cout << "new search? (0->no, 1->yes) ";
		if (ns==0) new_search=false;
		else new_search=true;
	}
	
	if (new_search==true)
	{
		cout << "enter starting address (hex): ";
		cin >> hex >> add_start;
		cout << "enter ending address (hex): ";
		cin >> add_end >> dec;
		
		cout << "enter size (0-> 1 byte, 1-> 2 bytes, 2-> 4 bytes): ";
		int temp;
		while (! (get_int(temp) && temp>=0 && temp<=2))
		cout << "enter size (0-> 1 byte, 1-> 2 bytes, 2-> 4 bytes): ";
		val_size=1;
		while (temp>0) 
		{
			val_size*=2; temp--;
		}
	}
	
	
	cout << "enter value: ";
	cin >> val;
	
	cout << "searching..." << endl;
	//system("pause");
	
	search_results[cur_result].clear();
	unsigned long i;
	int cur_val;
	
	int old_search_size=search_results[prev_result].size();
	
	
	cur_val=0;
	int count=0;
	for (i=add_start; i<=add_end; i++)
	{
		if (new_search==false)
		{
			if (count<old_search_size)
			{
				if (search_results[prev_result][count]==i) 
				{
					count++;
				}
				else continue;
			}
			else break;
		}
		
		
		ReadProcessMemory(phandle,(LPVOID)i,
                                 (LPVOID)&cur_val,val_size,0);
		if (val==cur_val)
		{
			cout << "value found at: " << hex << i << dec << endl; 
                        search_results[cur_result].push_back(i);
		}
		
	}
	
	if (search_results[cur_result].size()==0)
	cout << "no address with the desired value was found..." << endl;
	
	if (search_results[cur_result].size()==1)
	{
		int ans;
		cout << "create a label for this address? (0->no, 1->yes) ";
		while (!get_int(ans))
		cout << "create a label for this address? (0->no, 1->yes) ";
		if (ans!=0)
		{
			create_label(true,search_results[cur_result][0]);
		}
	}
	else if (search_results[cur_result].size()>1)
	{
		int ans;
		cout << "create a label for an address? (0->no, 1->yes) ";
		while (!get_int(ans))
		cout << "create a label for an address? (0->no, 1->yes) ";
		if (ans!=0)
		{
			create_label(false);
		}
	}
	
	cur_result^=(int)1;
	prev_result^=(int)1;
	new_search=false;
	system("pause");
}

void create_patch()
{
	Patch new_patch;
	cout << "enter patch description: ";
	cin.getline(new_patch.description,80,'\n');
	
	cout << "enter patch application address:"<< endl;
	get_address(new_patch.address);
	
	int ans;
	
	cout << "enter patch size (0-> 1 byte, 1-> 2 bytes, 2-> 4 bytes): ";
	while (! (get_int(ans) && ans>=0 && ans<=2))
	cout << "enter patch size (0-> 1 byte, 1-> 2 bytes, 2-> 4 bytes): ";
	new_patch.size=1;
	while (ans>0) 
	{
		new_patch.size*=2; ans--;
	}
	
	cout << "enter patch operation (0->assignment, 1->addition): ";
	while ( !(get_int(ans) && ans>=0 && ans<=1) )
	cout << "enter patch operation (0->assignment, 1->addition): ";
	new_patch.operation=ans;
	
	cout << "enter patch value type (0->constant, 1->address): ";
	while ( !(get_int(ans) && ans>=0 && ans<=1) )
	cout << "enter patch value type (0->constant, 1->address): ";
	new_patch.value_type=ans;
	
	cout << "enter patch type (0->static, 1->dynamic): ";
	while ( !(get_int(ans) && ans>=0 && ans<=1) )
	cout << "enter patch type (0->static, 1->dynamic): ";
	new_patch.patch_type=ans;
	
	if (ans==1)
	{
		patch_table.push_back(new_patch);
		cout << "patch added to patch-table succesfully!" << endl;
		return;
	}
	
	if (new_patch.value_type==0)
	{
		cout << "enter patch value (constant): ";
		while (!get_int(new_patch.value))
		cout << "enter patch value (constant): ";
	}
	else
	{
		cout << "enter patch value (address):"<< endl;
		get_address(new_patch.value);
		
	}
	
	patch_table.push_back(new_patch);
	cout << "patch added to patch-table succesfully!" << endl;
	system("pause");
}

void apply_patch()
{
	attach_update();
	if (!is_attached) 
	{
		cout << "dude, you are not attached to a process..." << endl;
		system("pause"); return;
	}
	
	if (patch_table.size()==0)
	{
		int ans;
		cout << "there are no patches in patch-table..." << endl;
		cout << "create a patch now? (0->no, 1->yes) ";
		while (!get_int(ans)) 
                cout << "create a patch now? (0->no, 1->yes) ";
		if (ans!=0) create_patch();
		else return;
	}
	
	int i;
	int patch_count=patch_table.size();
	for (i=0; i<patch_count; i++)
	{
		cout << "(" << i+1 << ") " << patch_table[i].description
                     << endl;
		
		if (i%10==9) system("pause");
	}
	
	
	cout << "apply which patch? (0-> cancel) ";
	int patch_id;
	while (!get_int(patch_id)) cout << "apply which patch? (0-> cancel) ";
	if (patch_id==0) return;
	if (patch_id<1 || patch_id>patch_count)
	{
		cout << "there is no such patch-id dude..." << endl;
		system("pause"); return;
	}
	int padd=patch_table[patch_id-1].address;
	int pval=patch_table[patch_id-1].value;
	int psize=patch_table[patch_id-1].size;
	
	int pop=patch_table[patch_id-1].operation;
	int pvt=patch_table[patch_id-1].value_type;
	int ppt=patch_table[patch_id-1].patch_type;
	
	int add_table_size=address_table.size();
	
	if (ppt==1)
	{
		if (pvt==0)
		{
			cout << "enter patch value (constant): ";
			while (!get_int(pval)) 
                        cout << "enter patch value (constant): ";
		}
		else
		{
			cout << "enter patch value (address):"<< endl;
			get_address(pval);
		}
	}
	
	if (pvt==1)
	{
		int temp;
		ReadProcessMemory(phandle,(LPVOID)pval,(LPVOID)&temp,psize,0);
		pval=temp;
	}
	if (pop==1)
	{
		int temp;
		ReadProcessMemory(phandle,(LPVOID)padd,(LPVOID)&temp,psize,0);
		pval+=temp;
	}
	
	if(WriteProcessMemory(phandle,(LPVOID)padd,(LPVOID)&pval,psize,0))
	cout << "patch applied succesfully, process memory modified!"<<endl;
	else
	cout << "unable to apply patch..." << endl;
	system("pause");
}

Code Part C:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
void view_patch_table()
{
	int size=patch_table.size();
	if (size==0) 
	{
		cout << "patch table is empty!..." << endl; system("pause");
                return;
	}
	
	int i;
	for (i=0; i<size; i++)
	{
		cout << "(" << i+1 << ") " << patch_table[i].description 
                     << endl;
		
		if (i%10==9) system("pause");
	}
	
	int patch_id;
	cout << "which patch? (0-> cancel) ";
	while (! (get_int(patch_id) && patch_id>=0 && patch_id<=size))
	cout << "which patch? (0-> cancel) ";
	if (patch_id==0) return;
	
	int choice;
	cout << "what to do? (0-> view, 1->erase) ";
	while (! (get_int(choice) && choice>=0 && choice<=1))
	cout << "what to do? (0-> view, 1->erase) ";
	
	if (choice==1)
	{
		patch_table.erase(
		patch_table.begin()+patch_id-1,patch_table.begin()+patch_id);
		cout << "patch succesfully erased!" << endl;
		system("pause");
		return;
	}
	
	//now choice==0
	Patch & my_patch=patch_table[patch_id-1];
	cout << "patch description: ";
	cout << my_patch.description << endl;
	cout << "application address: " << hex << my_patch.address << dec 
             << endl;
	cout << "patch size: " << my_patch.size << endl;
	cout << "patch operation: " << str_table_operation[my_patch.operation] 
             << endl;
	cout << "value type: " << str_table_value_type[my_patch.value_type] 
             << endl;
	cout << "patch type: " << str_table_patch_type[my_patch.patch_type] 
             << endl;
	
	if (my_patch.patch_type==0) //static patch
	{
		cout << "value: ";
		if (my_patch.value_type==1) cout << hex;//address value
		cout << my_patch.value;
		cout << dec;
		cout << endl;
	}
	system("pause");
	
}

void view_address_table()
{
	int size=address_table.size();
	if (size==0) 
	{
		cout << "address table is empty!..." << endl;
                system("pause"); 
                return;
	}
	
	int i;
	for (i=0; i<size; i++)
	{
		cout << "(" << i+1 << ") " << address_table[i].label << endl;
		
		if (i%10==9) system("pause");
	}
	
	int add_id;
	cout << "which address? (0-> cancel) ";
	while (! (get_int(add_id) && add_id>=0 && add_id<=size)) 
        cout << "which address? (0-> cancel) ";
	if (add_id==0) return;
	
	int choice;
	cout << "what to do? (0-> view, 1->erase) ";
	while (! (get_int(choice) && choice>=0 && choice<=1))
	cout << "what to do? (0-> view, 1->erase) ";
	
	if (choice==1)
	{
		address_table.erase(
		address_table.begin()+add_id-1,address_table.begin()+add_id);
		cout << "label succesfully erased!" << endl;
		system("pause");
		return;
	}
	//now choice==0
	
	Address & my_address=address_table[add_id-1];
	cout << "label: " << my_address.label << endl;
	cout << "address: " << hex << my_address.address << dec << endl;
	system("pause");
}

void save()
{
	int pt_size=patch_table.size();
	int at_size=address_table.size();
	
	if (pt_size==0 && at_size==0) 
	{
		cout << "nothing so save, dude..." << endl;
		system("pause"); return;
	}
	
	char filename[80];
	cout << "enter filename: ";
	cin.getline(filename,80,'\n');
	
	Patch my_patch;
	Address my_add;
	
	
	ofstream fout;
	fout.open(filename,ios::out|ios::binary);
	
	fout.write((char *)&(pt_size),4);
	int i;
	for (i=0; i<pt_size; i++)
	{
		strcpy(my_patch.description,patch_table[i].description);
		my_patch.address=patch_table[i].address;
		my_patch.value=patch_table[i].value;
		my_patch.size=patch_table[i].size;
		my_patch.operation=patch_table[i].operation;
		my_patch.value_type=patch_table[i].value_type;
		my_patch.patch_type=patch_table[i].patch_type;
		
		fout.write((char *)(my_patch.description),80);
		fout.write((char *)&(my_patch.address),4);
		fout.write((char *)&(my_patch.value),4);
		fout.write((char *)&(my_patch.size),1);
		fout.write((char *)&(my_patch.operation),1);
		fout.write((char *)&(my_patch.value_type),1);
		fout.write((char *)&(my_patch.patch_type),1);
	}
	
	fout.write((char *)&(at_size),4);
	for (i=0; i<at_size; i++)
	{
		strcpy(my_add.label,address_table[i].label);
		my_add.address=address_table[i].address;
		
		fout.write((char *)(my_add.label),80);
		fout.write((char *)&(my_add.address),4);
	}
	
	fout.close();
	cout << "tables saved succesfully!" << endl;
	system("pause");
}

void load()
{
	int pt_size;
	int at_size;
	
	char filename[80];
	cout << "enter filename: ";
	cin.getline(filename,80,'\n');
	
	Patch my_patch;
	Address my_add;
	
	ifstream fin;
        fin.open(filename,ios::in|ios::binary);
	
	patch_table.clear();
	address_table.clear();
	
	fin.read((char *)&(pt_size),4);
	
	int i;
	for (i=0; i<pt_size; i++)
	{
		fin.read((char *)(my_patch.description),80);
		fin.read((char *)&(my_patch.address),4);
		fin.read((char *)&(my_patch.value),4);
		my_patch.size=my_patch.operation=0;
		my_patch.value_type=my_patch.patch_type=0;
		fin.read((char *)&(my_patch.size),1);
		fin.read((char *)&(my_patch.operation),1);
		fin.read((char *)&(my_patch.value_type),1);
		fin.read((char *)&(my_patch.patch_type),1);
		
		patch_table.push_back(my_patch);
	}
	
	fin.read((char *)&(at_size),4);
	for (i=0; i<at_size; i++)
	{
		fin.read((char *)(my_add.label),80);
		fin.read((char *)&(my_add.address),4);
		
		address_table.push_back(my_add);
	}
	
	if (!fin)
	{
		fin.close();
		cout << "error while loading the tables..." << endl;
		patch_table.clear(); address_table.clear();
		system("pause"); return;
	}
	
	fin.close();
	cout << "tables loaded succesfully!" << endl;
	system("pause");
	
}
I wonder if someone bothers to actualy read all this...
Edit your first post and include some new lines.
This is not a place for ... nevermind it's not worth it.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
// Offset.cpp

#include <windows.h>
#include "Offset.hpp"

std::list<Offset::Patch_t*> Offset::m_PatchList;

DWORD
Offset::GetDllOffset(wchar_t* wszDllName, int nOffset)
{
	HMODULE hDll = GetModuleHandle(wszDllName) ? GetModuleHandle(wszDllName) : LoadLibrary(wszDllName);

	if(hDll)
		return nOffset < 0 ? reinterpret_cast<DWORD>(GetProcAddress(hDll, reinterpret_cast<LPSTR>((nOffset * -1)))) : reinterpret_cast<DWORD>(hDll) + nOffset;

	return 0;
}

bool
Offset::PatchCall(wchar_t* wszDllName, int nOffset, DWORD dwInterception, size_t Len)
{
	DWORD dwAddress = Offset::GetDllOffset(wszDllName, nOffset);

	if(dwAddress)
		return Offset::Patch(0xE8, dwAddress, dwInterception, Len);

	return false;
}

bool
Offset::PatchJump(wchar_t* wszDllName, int nOffset, DWORD dwInterception, size_t Len)
{
	DWORD dwAddress = Offset::GetDllOffset(wszDllName, nOffset);

	if(dwAddress)
		return Offset::Patch(0xE9, dwAddress, dwInterception, Len);

	return false;
}

bool Offset::Patch(byte bInstruction, DWORD dwAddress, DWORD dwInterception, size_t Len)
{
	DWORD dwOldProtect;
	DWORD dwRead;
	Patch_t* pPatch;
	BYTE* bCode = new byte[Len];

	if(bCode)
	{
		pPatch = new Patch_t;

		if(pPatch)
		{
			if(ReadProcessMemory(GetCurrentProcess(), reinterpret_cast<LPVOID>(dwAddress), pPatch->bBackup, Len, &dwRead) && dwRead == Len) 
			{
				pPatch->dwAddress = dwAddress;
				pPatch->Len = Len;
				Offset::m_PatchList.push_back(pPatch);

				memset(bCode, 0x90, Len);

				bCode[0] = bInstruction;
				*(DWORD*)&bCode[1] = dwInterception - (dwAddress + 5);

				VirtualProtect(reinterpret_cast<LPVOID>(dwAddress), Len, PAGE_EXECUTE_READWRITE, &dwOldProtect);
				memcpy_s(reinterpret_cast<LPVOID>(dwAddress), Len, bCode, Len);
				VirtualProtect(reinterpret_cast<LPVOID>(dwAddress), Len, dwOldProtect, &dwOldProtect);

				delete[] bCode;

				return true;
			}

			delete pPatch;
		}

		delete[] bCode;
	}

	return false;
}

bool
Offset::RemovePatches(void)
{
	DWORD dwWritten;

	if(!Offset::m_PatchList.empty())
	{
		for(std::list<Patch_t*>::iterator entry = Offset::m_PatchList.begin(); entry != Offset::m_PatchList.end(); entry++)
		{
			WriteProcessMemory(GetCurrentProcess(), reinterpret_cast<LPVOID>((*entry)->dwAddress), (*entry)->bBackup, (*entry)->Len, &dwWritten);
			delete (*entry);
		}

		Offset::m_PatchList.clear();

		return true;
	}

	return false;
}

DWORD
Offset::PatchVFT(LPVOID lpClass, DWORD dwIndex, DWORD dwFunction)
{
	DWORD dwOldProtect;
	DWORD dwOld;
	DWORD dwAddress = *(DWORD*)lpClass;

	if(dwAddress)
	{
		dwAddress += dwIndex * 4;

		VirtualProtect(reinterpret_cast<LPVOID>(dwAddress), 4, PAGE_EXECUTE_READWRITE, &dwOldProtect);
		dwOld = *(DWORD*)dwAddress;
		memcpy_s(reinterpret_cast<LPVOID>(dwAddress), 4, &dwFunction, 4);
		VirtualProtect(reinterpret_cast<LPVOID>(dwAddress), 4, dwOldProtect, &dwOldProtect);

		return dwOld;
	}

	return false;
}

DWORD
Offset::PatchIAT(HMODULE hModule, LPSTR lpszDll, LPSTR lpszFunc, DWORD dwFunction)
{
	IMAGE_DOS_HEADER *dosHd = reinterpret_cast<IMAGE_DOS_HEADER*>(hModule);
	IMAGE_NT_HEADERS *ntHd;	
	IMAGE_IMPORT_DESCRIPTOR* importDesc;
	DWORD dwOldProtect;
	DWORD dwOriginalFunction = reinterpret_cast<DWORD>(GetProcAddress(GetModuleHandleA(lpszDll), lpszFunc));

	if(dwOriginalFunction && dosHd && dosHd->e_magic == IMAGE_DOS_SIGNATURE)
	{
		ntHd = reinterpret_cast<IMAGE_NT_HEADERS*>(reinterpret_cast<DWORD>(dosHd) + dosHd->e_lfanew);
		
		if(ntHd->Signature == IMAGE_NT_SIGNATURE)
		{
			importDesc = reinterpret_cast<IMAGE_IMPORT_DESCRIPTOR*>(reinterpret_cast<DWORD>(dosHd) + ntHd->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);

			for(;importDesc->FirstThunk; importDesc++)
			{
				if(_strcmpi(lpszDll, reinterpret_cast<char*>((importDesc->Name + reinterpret_cast<DWORD>(dosHd)))))
					continue;
			
				for(IMAGE_THUNK_DATA* thunkData = reinterpret_cast<IMAGE_THUNK_DATA*>(importDesc->FirstThunk + reinterpret_cast<DWORD>(dosHd)); thunkData->u1.Function; thunkData++)
				{
					if(thunkData->u1.Function == dwOriginalFunction)
					{
						Patch_t* pPatch = new Patch_t;

						VirtualProtect(reinterpret_cast<LPVOID>(&thunkData->u1.Function), sizeof(DWORD), PAGE_EXECUTE_READWRITE, &dwOldProtect);

						pPatch->dwAddress = thunkData->u1.Function;
						pPatch->Len = sizeof(DWORD);
						memcpy(pPatch->bBackup, (&thunkData->u1.Function), sizeof(DWORD));
						m_PatchList.push_back(pPatch);

						thunkData->u1.Function = dwFunction;
						VirtualProtect(reinterpret_cast<LPVOID>(&thunkData->u1.Function), sizeof(DWORD), dwOldProtect, &dwOldProtect);
						return dwOriginalFunction;
					}
				}
			}
		}
	}
	return 0;
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// Offset.hpp

#pragma once

#include <list>

class Offset
{
	private:
		struct Patch_t
		{
			DWORD dwAddress;
			size_t Len;
			byte bBackup[64];
		};

		static std::list<Patch_t*> m_PatchList;

		static bool Patch(byte bInstruction, DWORD dwAddress, DWORD dwInterception, size_t Len);

	public:
		static DWORD GetDllOffset(wchar_t* wszDllName, int nOffset);
		static bool PatchCall(wchar_t* wszDllName, int nOffset, DWORD dwInterception, size_t Len);
		static bool PatchJump(wchar_t* wszDllName, int nOffset, DWORD dwInterception, size_t Len);
		static bool RemovePatches(void);

		static DWORD PatchVFT(LPVOID lpClass, DWORD dwIndex, DWORD dwFunction);
		static DWORD PatchIAT(HMODULE hModule, LPSTR lpszDll, LPSTR lpszFunc, DWORD dwFunction);
};
@indigo
you don't have to read the whole thing to get a grip on what's going on, really. Take a look at the structures in the beginning, the global vars and the declarations of the functions and you're mostly done. After all I explain its functionality before I post any piece of code. And my question is very specific and it's not directly related to the code I write here. I want the API that manipulates memory access status. I get the debug privilege in the beginning of main so I don't bother with memory access protection, but having full access everywhere proved to be inefficient as it takes a very long time to search everything. So I decided (especially after I saw those classifications of memory using the official Cheat Engine) to check the memory status before I search in it (for example if the memory status was "read-only" then it wouldn't make sense to search in there because a variable of a game wouldn't be stored in there). I could not post the code, but then some smartass would pop up and say "oh look, another kid who wants us to do his homework for him!!!"...

@DrChill
mmm... are all your comments on topics this elegant? I'd like to see them and if they are maybe I'll make a group on facebook about them :D Man, seriously, if u don't intend to help just don't post anything. It makes you look stupid and I suppose that's something you don't want (assuming, of course, that you are not stupid hahahaha :D )

@mackabee
thnx for the piece of code! I didn't quite get all of it (and I'd really like you to explain it, at least briefly, when you get the time) BUT I found an API call inside that helped answer my question :D I'm talking about VirtualProtect. I checked it on msdn and came up with the Virtual Memory Functions family. There's a function called VirtualQuerry which does the job I need! Thnx again!
And for anyone else who has the same problem, here are the related pages on msdn:

http://msdn.microsoft.com/en-us/library/aa366916%28VS.85%29.aspx
(Virtual Memory functions overview)

http://msdn.microsoft.com/en-us/library/aa366902%28VS.85%29.aspx
(VirtualQuerry function)

http://msdn.microsoft.com/en-us/library/aa366775%28VS.85%29.aspx
(MEMORY_BASIC_INFORMATION structure)
Last edited on
1
2
ReadProcessMemory(phandle,(LPVOID)i,
                                 (LPVOID)&cur_val,val_size,0);


You're calling ReadProcessMemory a BUNCH of times. For starters, call ReadProcessMemory with a big buffer and scan the memory buffer. Cutting the number of calls to ReadProcessMemory will considerably speed things up.

I'll explain the code I pasted sometime tonight if I have time.

Also, as good pratice, only call OpenProcess with the permissions you need. If you're compiling with VS2008 PROCESS_ALL_ACCESS value has been changed and doesn't do what it's suppose to. DON'T USE IT
Last edited on
Ok, I got that thing with the ReadProcessMemory. I'll try it. Thnx again!
@m4ster r0shi
Keep your 2 cents to yourself.

I meant to say something along the lines of this:

THIS IS NOT A PLACE TO POST YOUR "z0mg hax" IF YOU WANT TO, GO FIND SOME OTHER FORUM.
wow, I have to admit it... this guy has found a very smart and effective way to increase his post counter... way to go pal! you're gonna be a champ one day, I can tell... ;)
Last edited on
Eh it would probably be easier to explain those functions if you just asked me what you didn't understand.

VFT = Virtual Function Table
IAT = Import Address Table

These functions must be called from inside the process you want to modify (Inject your own DLL).

The list is used to store patches made so you can remove them all with RemovePatches.
Turned out it was the ReadProcessMemory calls that slowed it down... How didn't I see that?.. :/
I changed part of the code inside search() function to this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
//...
//more search() code before this point

	search_results[cur_result].clear();
	unsigned long i;
	int cur_val;
	
	int old_search_size=search_results[prev_result].size();
	
	char * buffer;
	int buffer_size;
	buffer_size=1000*val_size;
	buffer=new char[buffer_size];
	int buffer_times_read=0;
        unsigned long cur_add;
	
	int count=0;
	while (true)
	{
          
        ReadProcessMemory(phandle,reinterpret_cast<LPVOID>(add_start+buffer_times_read*buffer_size),
                                     reinterpret_cast<LPVOID>(buffer),buffer_size,0);  
        cur_val=0;
    	
    	for (i=0; i<buffer_size; i++)
        {
            cur_add=add_start+buffer_size*buffer_times_read+i;
            
    		if (new_search==false)
    		{
    			if (count<old_search_size)
    			{
    				if (search_results[prev_result][count]==cur_add) 
    				{
    					count++;
    				}
    				else continue;
    			}
    			else break;
    		}
    			
    		memcpy(&cur_val,buffer+i,val_size);
    	
    		
            if (val==cur_val)
    		{
    			cout << "value found at: " << hex << cur_add << dec << endl; 
                            search_results[cur_result].push_back(cur_add);
    		}
    		
    	}
    	
    	buffer_times_read++;
    	
    	if (add_end<cur_add+buffer_size) break;
    	
     }
     
     delete[] buffer;
     
	if (search_results[cur_result].size()==0)
	cout << "no address with the desired value was found..." << endl;
	
//more search() code after this point
//... 	


and it runs like hell! :D
I don't even think I'll be using VirtualQuerry at all... Ok, now that the problem is solved, I ll spend some time on reading your code carefully (with the msdn page open next to it hahaha :D ) and if I find things difficult I ll tell you. once again, thnx for the help! cya!...
Last edited on
It's best to use VirtualQueryEx and VirtualProtectEx to save memory range access, change it and then restore it back to the original protection.
Topic archived. No new replies allowed.