1 Star 0 Fork 0

phy0292/cheat-engine

加入 Gitee
与超过 1400万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
frmedithistoryunit.pas 12.22 KB
一键复制 编辑 原始数据 按行查看 历史
Dark Byte 提交于 2020-12-11 06:39 +08:00 . dark mode support
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564
unit frmEditHistoryUnit;
{$mode delphi}
interface
uses
{$ifdef darwin}
macport,
{$endif}
{$ifdef windows}
windows,
{$endif}
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs,
StdCtrls, ComCtrls, ExtCtrls, Menus, NewKernelHandler, syncobjs,
symbolhandler, lua, lauxlib, lualib, betterControls;
type
{ TfrmEditHistory }
TfrmEditHistory = class(TForm)
Button1: TButton;
cbLogWrites: TCheckBox;
edtMaxWriteLogSize: TEdit;
wlImageList: TImageList;
Label1: TLabel;
lvWriteLog: TListView;
miUndo: TMenuItem;
Panel1: TPanel;
PopupMenu1: TPopupMenu;
Timer1: TTimer;
procedure Button1Click(Sender: TObject);
procedure cbLogWritesChange(Sender: TObject);
procedure edtMaxWriteLogSizeChange(Sender: TObject);
procedure FormShow(Sender: TObject);
procedure lvWriteLogDblClick(Sender: TObject);
procedure miUndoClick(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
private
{ private declarations }
public
{ public declarations }
procedure refreshWriteLogView;
end;
TWriteLogEntry=class
public
id: integer;
address: ptruint;
originalsize: dword;
originalbytes: pbyte;
newsize: dword;
newbytes: pbyte;
destructor destroy; override;
end;
var
frmEditHistory: TfrmEditHistory;
logWrites: boolean=false;
procedure addWriteLogEntryToList(wle: TWriteLogEntry);
procedure setMaxWriteLogSize(size: integer);
procedure clearWriteLog;
procedure undoLastWrite;
procedure initializeLuaWriteLog;
function hasAddressBeenChanged(address: ptruint): boolean;
function hasAddressBeenChangedRange(startaddress, stopaddress: ptruint): boolean;
procedure undowrite(address: ptruint); overload;
implementation
{$R *.lfm}
uses MemoryBrowserFormUnit, ProcessHandlerUnit, globals, luahandler, LuaClass,
LuaByteTable, LuaObject, maps;
var
nextid: integer;
writelog: TList; //for a sorted list in the order it got changed
writelogmap: TMap; //for an address lookup to see if an address has been changed (holds every single byte)
writelogcs: TCriticalSection;
maxwritelogsize: integer=250;
{ TfrmEditHistory }
destructor TWriteLogEntry.destroy;
begin
if originalbytes<>nil then
FreeMemAndNil(originalbytes);
if newbytes<>nil then
FreeMemAndNil(newbytes);
inherited destroy;
end;
procedure removeBytesFromWriteLogMap(wle: TWriteLogEntry);
var
i: integer;
data: TObject;
a: ptruint;
oldwle: TWriteLogEntry;
begin
for i:=0 to wle.newsize-1 do
begin
a:=wle.address+i;
if writelogmap.GetData(a,data) then
begin
if data is TWriteLogEntry then //no list
writelogmap.Delete(a)
else //tlist
begin
tlist(data).Remove(wle);
if tlist(data).Count=1 then //no list needed anymore
begin
oldwle:=TWriteLogEntry(tlist(data)[0]);
tlist(data).free;
writelogmap.SetData(a,oldwle);
end;
end;
end;
end;
end;
procedure eraseWriteLogEntry(i: integer);
var wle: TWriteLogEntry;
begin
writelogcs.Enter;
try
if i<writelog.count then
begin
wle:=writelog[i];
writelog.Delete(i);
removeBytesFromWriteLogMap(wle);
wle.free;
end;
finally
writelogcs.Leave;
end;
end;
procedure clearWriteLog;
begin
while writelog.Count>0 do
eraseWriteLogEntry(writelog.count-1);
writelogmap.Clear; //should be empty already
end;
procedure addBytesToWriteLogMap(wle: TWriteLogEntry);
var
i: integer;
data: TObject;
newlist: TList;
a: ptruint;
begin
for i:=0 to wle.newsize-1 do
begin
a:=wle.address+i;
if writelogmap.GetData(a,data) then
begin
if data is TWriteLogEntry then
begin
//change the old entry to a list
newlist:=tlist.create;
newlist.add(data); //old entry first in the list
newlist.add(wle); //and now the new one
writelogmap.SetData(a, newlist);
end
else //tlist
tlist(data).Add(wle);
end
else
writelogmap.Add(a,wle);
end;
end;
procedure addWriteLogEntryToList(wle: TWriteLogEntry);
begin
wle.id:=nextid;
inc(nextid);
writelogcs.Enter;
try
if writelog.Count>maxwritelogsize then
eraseWriteLogEntry(0);
writelog.Add(wle);
addBytesToWriteLogMap(wle);
finally
writelogcs.leave;
end;
if (MainThreadID=GetCurrentThreadId) and (frmEditHistory<>nil) and (not frmEditHistory.Timer1.Enabled) then
frmEditHistory.Timer1.Enabled:=true;
end;
procedure setMaxWriteLogSize(size: integer);
begin
maxwritelogsize:=size;
while writelog.count>maxwritelogsize do
eraseWriteLogEntry(0);
end;
procedure undowriteInternal(id: integer); overload;
var i: integer;
wle: TWriteLogEntry;
x: ptruint;
oldprot: dword;
oldLogWrites: boolean;
vpe: boolean;
begin
writelogcs.enter;
try
for i:=0 to writelog.count-1 do
begin
wle:=TWriteLogEntry(writelog[i]);
if wle.id=id then
begin
vpe:=(SkipVirtualProtectEx=false) and VirtualProtectEx(processhandle, pointer(wle.address), wle.originalsize, PAGE_EXECUTE_READWRITE, oldprot);
oldLogWrites:=logWrites;
logWrites:=false;
WriteProcessMemory(processhandle, pointer(wle.address), wle.originalbytes, wle.originalsize, x);
logWrites:=oldLogWrites;
if vpe then VirtualProtectEx(processhandle, pointer(wle.address), wle.originalsize, oldprot, oldprot);
eraseWriteLogEntry(i);
break;
end;
end;
finally
writelogcs.leave;
end;
if frmEditHistory<>nil then
frmEditHistory.refreshWriteLogView;
end;
procedure undowrite(address: ptruint); overload;
var
data: TObject;
list: TList absolute data;
begin
if writelogmap.GetData(address, data) then
begin
if data is TWriteLogEntry then
undowriteInternal(TWriteLogEntry(data).id)
else
undowriteInternal(TWriteLogEntry(list[list.Count-1]).id);
end;
end;
procedure undoLastWrite;
begin
writelogcs.enter;
try
if writelog.Count>0 then
undowriteInternal(TWriteLogEntry(writelog[writelog.count-1]).id);
finally
writelogcs.leave;
end;
end;
procedure TfrmEditHistory.refreshWriteLogView;
var
i,j: integer;
wle: TWriteLogEntry;
e: tlistitem;
s: string;
selectedids: TIntegerSet;
mainselectedid: integer;
begin
if lvWriteLog.itemindex<>-1 then
mainselectedid:=integer(ptruint(lvWriteLog.items[lvWriteLog.ItemIndex].Data))
else
mainselectedid:=-1;
selectedids:=[];
for i:=0 to lvWriteLog.Items.Count-1 do
if lvWriteLog.Items[i].Selected then
selectedids:=selectedids+[integer(ptruint(lvWriteLog.Items[i].data))];
lvwritelog.BeginUpdate;
lvWriteLog.Clear;
writelogcs.enter;
try
for i:=0 to writelog.Count-1 do
begin
wle:=writelog[i];
e:=lvwritelog.Items.Add;
e.Caption:=symhandler.getNameFromAddress(wle.address);
s:='';
for j:=0 to wle.originalsize-1 do
s:=s+inttohex(wle.originalbytes[j],2)+' ';
e.SubItems.add(s);
s:='';
for j:=0 to wle.newsize-1 do
s:=s+inttohex(wle.newbytes[j],2)+' ';
e.SubItems.add(s);
e.Data:=pointer(wle);
end;
finally
writelogcs.leave;
end;
for i:=0 to lvwritelog.items.count-1 do
begin
if uintptr(lvWriteLog.Items[i].data) in selectedids then
lvWriteLog.Items[i].selected:=true;
if (mainselectedid<>-1) and (uintptr(lvWriteLog.Items[i].data)=mainselectedid) then
lvWriteLog.ItemIndex:=i;
end;
lvWriteLog.EndUpdate;
end;
procedure TfrmEditHistory.Button1Click(Sender: TObject);
begin
refreshWriteLogView;
end;
procedure TfrmEditHistory.cbLogWritesChange(Sender: TObject);
begin
logwrites:=cbLogWrites.checked;
end;
procedure TfrmEditHistory.edtMaxWriteLogSizeChange(Sender: TObject);
var v: integer;
begin
try
setMaxWriteLogSize(StrToInt(edtMaxWriteLogSize.text));
except
end;
end;
procedure TfrmEditHistory.FormShow(Sender: TObject);
begin
cbLogWrites.Checked:=logWrites;
edtMaxWriteLogSize.text:=inttostr(maxwritelogsize);
end;
procedure TfrmEditHistory.lvWriteLogDblClick(Sender: TObject);
begin
if lvWriteLog.Selected<>nil then
MemoryBrowser.disassemblerview.SelectedAddress:=symhandler.getAddressFromName(lvWriteLog.Selected.Caption);
end;
procedure TfrmEditHistory.miUndoClick(Sender: TObject);
var i: integer;
begin
for i:=lvWriteLog.items.count-1 downto 0 do
begin
if lvWriteLog.Items[i].Selected then
undowrite(TWriteLogEntry(lvWriteLog.Items[i].Data).address);
end;
end;
procedure TfrmEditHistory.Timer1Timer(Sender: TObject);
begin
timer1.enabled:=false;
refreshWriteLogView;
end;
//--------------------Lua-----------------
type
TWriteLog=class
private
function getWriteLogStatus: boolean;
procedure setWriteLogStatus(status: boolean);
function getWriteLogSize: integer;
procedure setWriteLogSize(size: integer);
public
published
property status: boolean read getWriteLogStatus write setWriteLogStatus;
property logsize: integer read getWriteLogSize write setWriteLogSize;
end;
var _writelog: TWriteLog;
function TWriteLog.getWriteLogStatus: boolean;
begin
result:=logWrites;
end;
procedure TWriteLog.setWriteLogStatus(status: boolean);
begin
logWrites:=status;
end;
function TWriteLog.getWriteLogSize: integer;
begin
result:=maxwritelogsize;
end;
procedure TWriteLog.setWriteLogSize(size: integer);
begin
maxwritelogsize:=size;
end;
function lua_getWriteLog(L:PLua_state): integer; cdecl;
begin
if _writelog=nil then
_writelog:=TWritelog.create;
luaclass_newClass(L,_writelog);
result:=1;
end;
function writelog_getLog(L:PLua_state): integer; cdecl;
var
wle: TWriteLogEntry;
i: integer;
begin
writelogcs.enter;
try
lua_newtable(L);
for i:=0 to writelog.count-1 do
begin
lua_pushinteger(L,i);
lua_newtable(L);
wle:=TWriteLogEntry(writelog[i]);
lua_pushstring(L, 'address');
lua_pushinteger(L, wle.address);
lua_settable(L,-3);
lua_pushstring(L, 'original');
CreateByteTableFromPointer(L, pbytearray(wle.originalbytes), wle.originalsize);
lua_settable(L,-3);
lua_pushstring(L, 'new');
CreateByteTableFromPointer(L, pbytearray(wle.newbytes), wle.newsize);
lua_settable(L,-3);
lua_settable(L,-3);
end;
result:=1;
finally
writelogcs.leave;
end;
end;
procedure writelog_addMetaData(L: PLua_state; metatable: integer; userdata: integer );
begin
object_addMetaData(L, metatable, userdata);
luaclass_addClassFunctionToTable(L, metatable, userdata, 'getLog', writelog_getLog);
end;
procedure initializeLuaWriteLog;
begin
luaclass_register(TWriteLog, writelog_addMetaData);
lua_register(LuaVM, 'getWriteLog', lua_getWriteLog);
end;
function hasAddressBeenChanged(address: ptruint): boolean;
begin
if logwrites then
result:=writelogmap.HasId(address)
else
result:=false;
end;
function hasAddressBeenChangedRange(startaddress, stopaddress: ptruint): boolean;
var i: integer;
startb: ptruint;
stopb: ptruint;
wle: TWriteLogEntry;
begin
if stopaddress-startaddress<writelog.count*4 then
begin
while startaddress<stopaddress do
begin
if hasAddressBeenChanged(startaddress) then
exit(true);
inc(startaddress);
end;
end
else
begin
//search the list
for i:=0 to writelog.count-1 do
begin
wle:=TWriteLogEntry(writelog[i]);
startb:=wle.address;
stopb:=wle.address+wle.newsize;
if ((startaddress < stopb) and (startb < stopaddress)) then
exit(true);
end;
end;
result:=false;
end;
initialization
writelog:=TList.create;
writelogmap:=TMap.Create(itsPtrSize, sizeof(TObject));
writelogcs:=TCriticalSection.create;
finalization
while writelog.count>0 do
eraseWriteLogEntry(writelog.count-1);
writelog.free;
writelogcs.free;
end.
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/phy0292/cheat-engine.git
git@gitee.com:phy0292/cheat-engine.git
phy0292
cheat-engine
cheat-engine
master

搜索帮助