Code:
unit MainUnit;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ImgList, Menus, ComCtrls, ToolWin, ExtCtrls, TlHelp32, StdCtrls, AppEvnts;
// This type can hold an offset and the size of the data to be read. It is
// used a lot in the search and seive functions.
TMappedAddress = Record
dwAddress : Cardinal;
dwSize : Cardinal;
End;
// Used to allocate new cheats dynamically
PCheat = ^TCheat;
// Holds info about each cheat
TCheat = Record
Address, Value : Cardinal;
Size : Byte;
Freeze : Boolean;
Description : String[50];
end;
// This just tells us what the current data type to search for is. It is used
// to autoselect a Data Type in the seive and find dialogs.
SearchMode = (smByte, smWord, smDWORD);
// The range type
SearchRange = (srWin16, srWin32);
var
Process : TProcessEntry32; // This holds info about the open process
Mapped : Array of TMappedAddress; // This holds all the info about the R/W memory blocks
iSC : Integer; // The number of R/W blocks in Mapped
List : TList; // The list of results from the search
Mode : SearchMode; // The current search mode (smByte, smWord, smDword)
FoundIn : Array of Boolean; // This keeps track of where results were found (speeds things up)
Cheats : TList; // This holds a list of pointers to the cheats
bIsDirty : Boolean; // This keeps track of whether the cheat list has been changed (needs saving)
MaxResults : Integer; // Specifies the maximum number of results to display
Range : SearchRange; // The range of memory to search
implementation
uses SelectProcessUnit, SearchingUnit, AboutUnit, FindUnit, IniFiles, AddCheatUnit,
OptionsUnit, TCUnit;
{$R *.DFM}
// This converts a hex string back to an integer
Function HexToInt(HexString : String) : integer;
begin
// Add a "$" to the hex string. Delphi uses "$" incstead of C++'s
// "0x" to denote hex values
HexString := '$' + HexString;
// Use Delphi's built-in StrToInt function to convert the hex string back to
// an integer.
Result := StrToInt(HexString);
end;
Procedure TMainForm.FindValue(Data : Integer; Size : Byte; BufferSize : Integer);
var
hProcess : THandle;
iCurBlock : Integer;
iCurByte : Integer;
iBytesRead : Cardinal;
Bytes : Array of Byte;
dwStart, dwStop : DWORD;
iResultCount : Cardinal;
d, e : Cardinal;
i : integer;
xByte : Byte;
xWord, xWord2 : Word;
xDword, xDword2 : DWORD;
Form : TSearchingForm;
Item : TListItem;
SaveCursor : TCursor;
begin
// Assign the value to the correct variable
Case Size Of
1:
xByte := Data;
2:
xWord := Data;
4:
xDword := Data;
Else
begin
ShowMessage('Bad data size!');
Exit;
end;
End;
Timer.Enabled := False;
SaveCursor := Screen.Cursor;
Screen.Cursor := crHourglass;
// Clear and free the current list of results
List.Clear;
List.Free;
// Clear the listview with the results
Results.Items.Clear;
// Create the list again
List := TList.Create;
// Create the status form
Form := TSearchingForm.Create(Self);
// Show the status form
Form.Show;
// Map the R/W memory locations and optimize them
MapMemory(BufferSize, Size);
// Set the max to the number of blocks to search
Form.Progress.Max := iSC;
// Set the size of the buffer to the buffer size
SetLength(Bytes, BufferSize + (Size - 1));
SetLength(FoundIn, iSC);
// Open the process
hProcess := OpenProcess(PROCESS_VM_READ, False, Process.th32ProcessID);
//Get the start time
dwStart := GetTickCount;
iResultCount := 0;
MainForm.Enabled := False;
Case Size of
1:
begin
// Loop through all the blocks
For iCurBlock := 0 to iSC-1 do
begin
// Read a block into memory
ReadProcessMemory(hProcess, Pointer(Mapped[iCurBlock].dwAddress), @Bytes[0], Mapped[iCurBlock].dwSize, iBytesRead);
For iCurByte := 0 to iBytesRead-1 do
begin
// Check for a match
If Bytes[iCurByte] = xByte then
begin
List.Add(Pointer(Mapped[iCurBlock].dwAddress + iCurByte));
FoundIn[iCurBlock] := True;
end;
end;
// Only update the screen every 100 blocks
If iCurBlock mod 100 = 0 then
begin
Form.Status.Caption := 'Searching block ' + IntToStr(iCurBlock+1) + ' of ' + IntToStr(iSC);
Form.Progress.Position := Form.Progress.Position + 100;
Status.Panels[0].Text := IntToStr(List.Count) + ' Results';
// Process the applications message que so the user can SEE the updated staus
Application.ProcessMessages;
end;
end;
end;
2:
begin
// Loop through all the blocks
For iCurBlock := 0 to iSC-1 do
begin
// Read a block into memory
ReadProcessMemory(hProcess, Pointer(Mapped[iCurBlock].dwAddress), @Bytes[0], Mapped[iCurBlock].dwSize, iBytesRead);
For iCurByte := 0 to iBytesRead-(Size-1) do
begin
// Check for a match
CopyMemory(@xWord2, @Bytes[iCurByte], 2);
If xWord2 = xWord then
begin
List.Add(Pointer(Mapped[iCurBlock].dwAddress + iCurByte));
FoundIn[iCurBlock] := True;
end;
end;
// Only update the screen every 100 blocks
If iCurBlock mod 100 = 0 then
begin
Form.Status.Caption := 'Searching block ' + IntToStr(iCurBlock+1) + ' of ' + IntToStr(iSC);
Form.Progress.Position := Form.Progress.Position + 100;
Status.Panels[0].Text := IntToStr(List.Count) + ' Results';
// Process the applications message que so the user can SEE the updated staus
Application.ProcessMessages;
end;
end;
end;
4:
begin
// Loop through all the blocks
For iCurBlock := 0 to iSC-1 do
begin
// Read a block into memory
ReadProcessMemory(hProcess, Pointer(Mapped[iCurBlock].dwAddress), @Bytes[0], Mapped[iCurBlock].dwSize, iBytesRead);
For iCurByte := 0 to iBytesRead-(Size-1) do
begin
// Check for a match
CopyMemory(@xDword2, @Bytes[iCurByte], 4);
// Compare the values
If xDword2 = xDword then
begin
List.Add(Pointer(Mapped[iCurBlock].dwAddress + iCurByte));
FoundIn[iCurBlock] := True;
end;
end;
// Only update the screen every 100 blocks
If iCurBlock mod 100 = 0 then
begin
Form.Status.Caption := 'Searching block ' + IntToStr(iCurBlock+1) + ' of ' + IntToStr(iSC);
Form.Progress.Position := Form.Progress.Position + 100;
Status.Panels[0].Text := IntToStr(List.Count) + ' Results';
// Process the applications message que so the user can SEE the updated staus
Application.ProcessMessages;
end;
end;
end;
end;
// Get the stop time
dwStop := GetTickCount;
Form.Status.Caption := 'Searching block ' + IntToStr(iCurBlock+1) + ' of ' + IntToStr(iSC);
Form.Progress.Position := Form.Progress.Max;
// Process the applications message que so the user can SEE the updated staus
Application.ProcessMessages;
// Close the object handle
CloseHandle(hProcess);
// Free the memory taken up by our temp buffer
Finalize(Bytes);
FreeMem(Bytes);
// Say how many results we got
Status.Panels[0].Text := IntToStr(List.Count) + ' Results';
MainForm.Enabled := True;
// Free the status form
Form.Free;
// Only show the results if under 50 were found
If (List.Count <= MaxResults) and (List.Count > 0) then
begin
For i := 0 to List.Count-1 do
begin
Item := Results.Items.Add;
Item.Caption := IntToHex(Integer(List.Items[i]), 8);
Item.SubItems.Add(IntToStr(Data));
SieveResultsMenu.Enabled := True;
SeiveResultsButton.Enabled := True;
end;
end
else
if List.Count > MaxResults then
begin
MessageBox(Handle, 'Too many results were found! They won''t be shown. Try using the Sieve Search to lower the range.', 'Search Results', MB_ICONINFORMATION);
SieveResultsMenu.Enabled := True;
SeiveResultsButton.Enabled := True;
end
else
if List.Count = 0 then
begin
MessageBox(Handle, 'No results were found!', 'Search Results', MB_ICONERROR);
SieveResultsMenu.Enabled := False;
SeiveResultsButton.Enabled := False;
end;
Timer.Enabled := True;
Screen.Cursor := SaveCursor;
end;
Procedure TMainForm.MapMemory(BufferSize : Integer; DataSize : Integer);
var
hProcess : THandle;
MBI : MEMORY_BASIC_INFORMATION;
dwAddress : DWORD;
iR : Integer;
iBlock : Integer;
cTotalSize : integer;
iSaved : Cardinal;
MaxAddy : Cardinal;
begin
Finalize(Mapped);
FreeMem(Mapped);
cTotalSize := 0;
iSaved := 0;
iSC := 0;
SetLength(Mapped, 0);
if Range = srWin32 then
begin
dwAddress := $400000;
MaxAddy := $80000000;
end
else
begin
dwAddress := $80000000;
MaxAddy := $FFFFFFF;
end;
hProcess := OpenProcess(PROCESS_QUERY_INFORMATION, False, Process.th32ProcessID);
While (VirtualQueryEx(hProcess, Pointer(dwAddress), MBI, SizeOf(MEMORY_BASIC_INFORMATION)) > 0) and (Integer(MBI.BaseAddress) + MBI.RegionSize < MaxAddy) do
begin
If (MBI.Protect = PAGE_READWRITE) and (MBI.Type_9 = MEM_PRIVATE) and ((MBI.State = MEM_COMMIT) or (MBI.State = MEM_RESERVE)) Then
begin
iR := MBI.RegionSize;
iBlock := 0;
Repeat
If iR <= BufferSize then
begin
If iBlock > 0 then
MBI.BaseAddress := Pointer(Integer(MBI.BaseAddress) - (DataSize - 1));
inc(iSC);
SetLength(Mapped, iSC);
Mapped[iSC-1].dwAddress := Integer(MBI.BaseAddress) + (MBI.RegionSize - iR);
if iBlock > 0 then
Mapped[iSC-1].dwSize := iR + (DataSize - 1)
else
Mapped[iSC-1].dwSize := iR;
iR := 0;
end
else
begin
If iBlock > 0 then
MBI.BaseAddress := Pointer(Integer(MBI.BaseAddress) - (DataSize - 1));
inc(iSC);
SetLength(Mapped, iSC);
Mapped[iSC-1].dwAddress := Integer(MBI.BaseAddress) + (MBI.RegionSize - iR);
if iBlock > 0 then
Mapped[iSC-1].dwSize := BufferSize + (DataSize - 1)
else
Mapped[iSC-1].dwSize := BufferSize;
inc(iBlock);
iR := iR - BufferSize;
end;
Until iR = 0;
inc(cTotalSize, MBI.RegionSize);
end;
Inc(dwAddress, MBI.RegionSize);
end;
CloseHandle(hProcess);
end;
end.