下面有一个摘录的资料:(好像是做patch的原理的,不过应该有帮助吧) 另外,我个人的意见,可不可以用writeprocessmemory函数呢? The Unofficial Newsletter of Delphi Users - by Robert Vivrette -------------------------------------------------------------------------------- Self-Modifying Code With Delphi by Marcus M?nnig - [email protected] Preface Lots of people using high-level languages, like Object Pascal, do not know much about what happens with their code when they click compile in Delphi. If you have a basic knowledge about assembler and about the exe file format, the comments in the source code should make everything pretty clear. For everyone else, I will try to explain what's done in the source code. My own knowledge about assembler and the exe format is limited and I learned most of it while looking for information about piracy protection and how to implement self-modifying code myself. The reason why I did this article is that I found very little information about this issue, so I put everything I found together to share it. Further, english is not my native language, so excuse any spelling and grammatical mistakes. Self-modifying code with Delphi What is it? Normally, we modify our code at design time. This usually happens inside Delphi before the code is compiled. Well, we all know this. Then, sometimes compiled code gets modified, e.g. a patch might be applied to a (non-running) exe file to do changes to the original exe. This is often used when applications are distributed widely and the users want to update to a newer version. To save download time and to prevent that the user has to reinstall the whole application again, only the differences between two versions of an exe file are distributed in a patch file an applied to the old version of the exe. Another example of patch files are "cracks"... little com or exe files that remove built-in limitations (evaluation time limits, etc.) from applications. These two kinds of code modifications are obviously done before the exe is executed. When an exe file is executed the file gets loaded into memory. The only way to affect the behavior of the program after this point is to modify the memory where the exe now resides. A program that modifies itself while it is running by doing changes to the memory uses "self-modifying code". Why is it bad? Self-modifying code makes debugging harder, since there is a difference in what is in the memory and what the debugger thinks is in the memory. Self-modifying code also has a bad reputation, especially because the most prominent use for it are viruses, that do all kinds of hide and seek tricks with it. This also means that if you use self-modifying code it's always possible that a virus checker will complain about your application. Why is it good? Self-modifying code makes debugging harder. While this is bad if you want to debug your code, it's good to prevent others from debugging your code or at least make it harder for them. This is the reason why self-modifying code can be an effective part of a piracy protection scheme. It won't prevent that an application can be cracked, however a wise use of this technique can make it very hard. What functions are needed? In a Windows environment we can make use the following API calls: ReadProcessMemory(hProcess,lpBaseAddress,lpBuffer,nSize,lpNumberOfBytesRead); This function is used, well, to read the memory of a process. Since this article is about _self_-modifying code, we will always use this function on our process only. WriteProcessMemory(hProcess,lpBaseAddress,lpBuffer,nSize,lpNumberOfBytesWritten); Used for writing data to a process memory. VirtualProtect(lpAddress,dwSize,flNewProtect,lpflOldProtect); Used to change the access protection of a region in memory. To learn more about these functions, refer to the Win32 help file that ships with Delphi and take a look how they are used in the sample code. What does the example code do? The code that will be modified is inside the CallModifiedCode procedure: procedure TForm1.CallModifiedCode(Sender: TObject); var b:boolean; c:TColor; label 1; begin c := clgreen; b := true; if b then goto 1; asm nop nop nop nop nop nop end; c := clred; 1: form1.Color := c; end;After studying the code you might be puzzled about some things. Obviously, this code sets the color of Form1, but as it is, the color will always be green, since b is always true, so it will always jump to label 1 and c:=clred before never gets called. However, there is another function in the program that will change the line if b then goto 1; to if NOT(b) then goto 1; while the program is running, so after this modification in memory is done and this function is called again the form will actually be changed to red. Note that we will not change the boolean value of b, but virtually insert a "NOT" into the if statement. Surely you noticed the six "nop"'s. "nop" is an assembler instruction and means "no operation", so these 6 lines do just nothing. 6 nop's in a row are quite unusual in a compiled exe, so we will use these nops as a er for the position of the if statement above inside the compiled exe. To understand how we will modify the code, we need to take a look at what the compiler will make from our pascal code. You can do this by running the project from Delphi, setting a breakpoint on the line with the if statement and (once you called the CallModifiedCode procedure by clicking the button and the debugger stopped the execution) opening the CPU window from Delphi's debug menu. You will see something like this: 807DFB00 cmp byte ptr [ebp-$05],$00 750D jnz TForm1.CallModifiedCode + $2A 90 nop 90 nop 90 nop 90 nop 90 nop 90 nop Well, we can clearly see the 6 nops we placed in our code. The two lines above are the assembler code of the if statement. The first line compares a value (as we know from the pascal code this has to be the boolean value of b) with $00, the hexadecimal notation of 0, that in the case of a boolean variable means false. The second line starts with jnz, what means "jump if not equal" (technically, "jump if not zero") and the address to jump to if the compared values from line one are not equal. So, the first two lines mean: "Compare the value of variable b with 0 (false) and if they are not equal jump away." Note the hexadecimal values to the left of the asm code above. Each assembler instruction has a unique hexadecimal identifier. Obviously, $90 means "nop". $75 means "jnz", which is followed by the address (relative to the current address) to jump to ($0D in this case). $80 means "cmp" followed by some hexadecimal data specifying what and how it it compared. This hexadecimal representation of the assembler instructions is what makes the exe. If you have a hex editor, load the compiled exe and try to search for "909090909090". You will quickly find it and you will notice that the values before will be identical with the values above. So, coming back to our task, if we want to insert "NOT" into our if statement, we will need to replace "jnz" with "jz". "jz" means "jump if zero" or "jump if equal". Replacing "jnz" with "jz" will reverse the condition in the original if statement, so once this modification is done the jump will not be done and the line c:=clRed; will be executed and the form will get red. As I said, "jnz" is represented by the hexadecimal value $75. The hexadecimal value for "jz" is $74. Let's summarize what we have to do to change "if b then goto 1;" to "if NOT(b) then goto 1;": Locate $909090909090 in memory. From this position, go back two bytes and replace $75 with $74. If we want to go back to the original code, we do the same, but replace $74 with $75. This is what is done in procedure TForm1.ModifyCode. I'll not go into further details here, but the source has lots of comments. You can download the sample code for this article by clicking here. After calling ModifyCode by clicking one of the two buttons on the right, click the "Execute code" button again and open the CPU view in Delphi to see that $75 was actually replaced with $74 or vice versa. Epilog There are easier ways to set the color of a form depending on which button was clicked ;-), but of course the purpose here is to demonstrate the concept of self-modifying code. Self-modifying code is a powerful technique and the example code might be very useful to implement a piracy protection scheme. Finally, a small warning: You should take care when using a series of assembler nop's as a er in real world applications, as these kind of unused code sections can be a nest for some viruses, e.g. the W95/CIH1003 virus.
前几天才刚刚在Borland的新闻组里看到这个,以下的源代码已经过测试。 运行环境:WIN98+D5 将代码编译好后,把EXE文件拷贝到一张空白的软盘里面,然后从软件里执行这个程序就可以了。 它是用写磁盘绝对位置的方法来修改EXE文件的。 ////////////////////////////// 运行时改变自身文件的代码 Here is source code that will create a delphi app that can write to it's own exe file on disk while it runs... win9x only... but you can do the same thing on 95-->xp if you code a different direct sector routine. It's not magic at all... but it works... Just format a fresh and clean floppy and then compile this code and copy it to the disk... then run it and type in a new DOS stub message in the edit box and press the button... the next time you run the program it will display the DOS stub txt that you entered as it's caption. This simple minded demo does not look for the sectors that contain your exe because you have placed it on a fresh 1.44 floppy and it know that the dos stub code is in sector 33 :-) but you can code a routine to find all the sectors of an exe on a hd and use the same sort of code to alter all of them... I worked on a program that downloaded updates from the web and installed them into the running programs exe file... it worked but when I ran it all night doing constant updates on the exe while running a disk defrag it wound up corrupting the hd :-( so I abandoned the scheme in favor of the much safer trick of just appearing to alter an exe's file while it runs....here is the code... I hope the text formats correctlyunit Unit1; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ComCtrls;type TForm1 = class(TForm) Button1: TButton; Edit1: TEdit; Label1: TLabel; procedure Button1Click(Sender: TObject); procedure FormCreate(Sender: TObject); private public end;var Form1: TForm1;const VWin32_DIOC_DOS_Int25 = 2; // direct read access VWin32_DIOC_DOS_Int26 = 3; // direct write accesstype TDevIoCtl_Reg = packed Record Reg_EBX : DWord; Reg_EDX : DWord; Reg_ECX : DWord; Reg_EAX : DWord; Reg_EDI : DWord; Reg_ESI : DWord; Reg_Flags : DWord; end;type TDiskIO = packed record StartSektor : DWord; AnzahlSektoren : Word; PBuffer : DWord; end;implementation{$R *.DFM}//Demo program that writes new data to the PE //of a running delphi exe WHILE IT IS RUNNING! :-) //To use this demo just freshly format a standard //1.44 mb floppy disk and then copy this exe to it //run it from the floppy and it can alter itself //by writting a new DOS stub Message to the exe's file //on the disk ... the next time the program is run the //new stub text will be in the caption :-) //To do this on a HD just discern the location of the //disk sector that contains the first 512 bytes of this exe //you can get this from the dir/fat data... this disk code //only works on fat 16 hd's so you need to recode for fat32 //This is meant to be a demo that proves that contrary to //popular opinion an exe can write to it's own file while //running!... but just because something CAN be done does //not mean that it SHOULD be done! ... you will likely //wind up destroying data on a HD if you write code to //locate an exe on the hd and alter it directly...WinDoze //is totally blind to the fact that you are writing data //to the sectors directly and will happily move things about //while you are doing it... and you will wind up overwritting //the wrong data sooner or later :-(procedure TForm1.Button1Click(Sender: TObject); var x: Integer; DevIoHandle : THandle; BytesReturned : DWord; Reg : TDevIoCtl_Reg; DiskIO : TDiskIO; DatenBuffer : Array [0..511] of Byte; // = 512 Bytesbegin if (length(edit1.text)>35) or (length(edit1.text)=0) then begin showmessage('Please enter a new DOS stub text of 1 to 35 chars!'); exit; end; with DiskIO do begin StartSektor := 33; // from sector 33 AnzahlSektoren := 1; // read 1 sector PBuffer := DWord(@DatenBuffer); end; with Reg do begin Reg_EAX := 0; // drive: 0 = A, 1 = B etc. Reg_EBX := DWord(@DiskIO); Reg_ECX := $FFFF; // use DiskIO end; DevIoHandle := CreateFile( '\\.\vwin32', Generic_Read, File_Share_Read or File_Share_Write, nil, Open_Existing, File_Attribute_Normal, 0); if DevIoHandle <> Invalid_Handle_Value then begin DeviceIoControl(DevIoHandle, VWin32_DIOC_DOS_Int25, @Reg, SizeOf(Reg), @Reg, SizeOf(Reg), BytesReturned, nil); for x := 80 to 80 + length(edit1.text) do begin DatenBuffer[x] := ord(edit1.text[x-79]); end; DeviceIoControl(DevIoHandle, VWin32_DIOC_DOS_Int26, @Reg, SizeOf(Reg), @Reg, SizeOf(Reg), BytesReturned, nil); CloseHandle(DevIoHandle); end; end;procedure TForm1.FormCreate(Sender: TObject); Var x: Byte; begin Form1.Caption := ''; For X := 80 to 115 do begin Form1.Caption := Form1.Caption + Char(pointer(Hinstance+X)^); end; end; end.================ I will zip up a file with all the source files and put it in the attachements group....this will make it easier for anyone that wants to build this silly little demo :-)
p.s. In the program I wrote to auto-update from the web I was compressing a 500kb delphi app down to 170kb using UPX... then I padded out the compressed file back to the original 500kb using 00H bytes.. this file would then pkzip down to about 160kb because all the 00H's scrunched down to nearly nothing... this gave me a large space to build out a large update into and let me avoid altering the fat because there was plenty of useable room in the original file...the already allocated sectors were always able to hold a larger updated exe...and all the 00H bytes had no ill effect on the exe before or after an update :-)
writeprocessmemory不能在Win9X中使用
to eDRIVE: writeprocessmemory至少就能够在win95中使用,你可以打开win32 SDK help看看 writeprocessmemory的quick info内容。 这是一个平台无关的函数(NT、9x下都支持)
能告诉你的主页地址吗,我也想知道。
另外,我个人的意见,可不可以用writeprocessmemory函数呢?
The Unofficial Newsletter of Delphi Users - by Robert Vivrette --------------------------------------------------------------------------------
Self-Modifying Code With Delphi by Marcus M?nnig - [email protected] Preface Lots of people using high-level languages, like Object Pascal,
do not know much about what happens with their code when they
click compile in Delphi. If you have a basic knowledge about
assembler and about the exe file format, the comments in the
source code should make everything pretty clear. For everyone
else, I will try to explain what's done in the source code. My own knowledge about assembler and the exe format is limited
and I learned most of it while looking for information about
piracy protection and how to implement self-modifying code myself.
The reason why I did this article is that I found very little
information about this issue, so I put everything I found together
to share it. Further, english is not my native language, so excuse
any spelling and grammatical mistakes. Self-modifying code with Delphi What is it? Normally, we modify our code at design time. This
usually happens inside Delphi before the code is compiled. Well,
we all know this. Then, sometimes compiled code gets modified, e.g. a patch might
be applied to a (non-running) exe file to do changes to the
original exe. This is often used when applications are distributed
widely and the users want to update to a newer version. To save
download time and to prevent that the user has to reinstall the
whole application again, only the differences between two versions
of an exe file are distributed in a patch file an applied to the
old version of the exe. Another example of patch files are "cracks"...
little com or exe files that remove built-in limitations (evaluation
time limits, etc.) from applications. These two kinds of code modifications are obviously done before the
exe is executed. When an exe file is executed the file gets loaded
into memory. The only way to affect the behavior of the program
after this point is to modify the memory where the exe now resides. A program that modifies itself while it is running by doing changes
to the memory uses "self-modifying code". Why is it bad? Self-modifying code makes debugging harder, since there is a difference
in what is in the memory and what the debugger thinks is in the memory. Self-modifying code also has a bad reputation, especially because
the most prominent use for it are viruses, that do all kinds of hide
and seek tricks with it. This also means that if you use self-modifying
code it's always possible that a virus checker will complain about
your application. Why is it good? Self-modifying code makes debugging harder. While this is bad if you
want to debug your code, it's good to prevent others from debugging
your code or at least make it harder for them. This is the reason
why self-modifying code can be an effective part of a piracy protection
scheme. It won't prevent that an application can be cracked, however
a wise use of this technique can make it very hard. What functions are needed? In a Windows environment we can make use the following API calls: ReadProcessMemory(hProcess,lpBaseAddress,lpBuffer,nSize,lpNumberOfBytesRead);
This function is used, well, to read the memory of a process. Since this
article is about _self_-modifying code, we will always use this function
on our process only.
WriteProcessMemory(hProcess,lpBaseAddress,lpBuffer,nSize,lpNumberOfBytesWritten);
Used for writing data to a process memory.
VirtualProtect(lpAddress,dwSize,flNewProtect,lpflOldProtect);
Used to change the access protection of a region in memory. To learn more
about these functions, refer to the Win32 help file that ships with Delphi
and take a look how they are used in the sample code.
What does the example code do? The code that will be modified is inside the CallModifiedCode procedure: procedure TForm1.CallModifiedCode(Sender: TObject);
var
b:boolean;
c:TColor;
label 1;
begin
c := clgreen;
b := true;
if b then goto 1;
asm
nop
nop
nop
nop
nop
nop
end;
c := clred;
1:
form1.Color := c;
end;After studying the code you might be puzzled about some things.
Obviously, this code sets the color of Form1, but as it is, the
color will always be green, since b is always true, so it will
always jump to label 1 and c:=clred before never gets called.
However, there is another function in the program that will
change the line if b then goto 1; to if NOT(b) then goto 1;
while the program is running, so after this modification in
memory is done and this function is called again the form will
actually be changed to red. Note that we will not change the
boolean value of b, but virtually insert a "NOT" into the if statement. Surely you noticed the six "nop"'s. "nop" is an assembler instruction
and means "no operation", so these 6 lines do just nothing. 6 nop's
in a row are quite unusual in a compiled exe, so we will use these
nops as a er for the position of the if statement above inside
the compiled exe. To understand how we will modify the code, we need to take a look at
what the compiler will make from our pascal code. You can do this by
running the project from Delphi, setting a breakpoint on the line with
the if statement and (once you called the CallModifiedCode procedure by
clicking the button and the debugger stopped the execution) opening the
CPU window from Delphi's debug menu. You will see something like this: 807DFB00 cmp byte ptr [ebp-$05],$00
750D jnz TForm1.CallModifiedCode + $2A
90 nop
90 nop
90 nop
90 nop
90 nop
90 nop
Well, we can clearly see the 6 nops we placed in our code. The two lines
above are the assembler code of the if statement. The first line compares
a value (as we know from the pascal code this has to be the boolean value
of b) with $00, the hexadecimal notation of 0, that in the case of a
boolean variable means false.
The second line starts with jnz, what means "jump if not equal" (technically,
"jump if not zero") and the address to jump to if the compared values
from line one are not equal. So, the first two lines mean: "Compare the
value of variable b with 0 (false) and if they are not equal jump away." Note the hexadecimal values to the left of the asm code above. Each assembler
instruction has a unique hexadecimal identifier. Obviously, $90 means "nop". $75
means "jnz", which is followed by the address (relative to the current address)
to jump to ($0D in this case). $80 means "cmp" followed by some hexadecimal data
specifying what and how it it compared. This hexadecimal representation of the
assembler instructions is what makes the exe. If you have a hex editor, load
the compiled exe and try to search for "909090909090". You will quickly find
it and you will notice that the values before will be identical with the values above. So, coming back to our task, if we want to insert "NOT" into our if statement,
we will need to replace "jnz" with "jz". "jz" means "jump if zero" or
"jump if equal". Replacing "jnz" with "jz" will reverse the condition
in the original if statement, so once this modification is done the jump
will not be done and the line c:=clRed; will be executed and the form
will get red. As I said, "jnz" is represented by the hexadecimal value $75.
The hexadecimal value for "jz" is $74. Let's summarize what we have to do to change "if b then goto 1;" to "if NOT(b)
then goto 1;": Locate $909090909090 in memory. From this position, go back
two bytes and replace $75 with $74. If we want to go back to the original
code, we do the same, but replace $74 with $75. This is what is done in procedure TForm1.ModifyCode. I'll not go into further
details here, but the source has lots of comments. You can download the sample
code for this article by clicking here. After calling ModifyCode by clicking
one of the two buttons on the right, click the "Execute code" button again
and open the CPU view in Delphi to see that $75 was actually replaced with
$74 or vice versa. Epilog There are easier ways to set the color of a form depending on which
button was clicked ;-), but of course the purpose here is to demonstrate
the concept of self-modifying code. Self-modifying code is a powerful
technique and the example code might be very useful to implement a
piracy protection scheme. Finally, a small warning: You should take care when using a series
of assembler nop's as a er in real world applications, as
these kind of unused code sections can be a nest for some viruses,
e.g. the
W95/CIH1003 virus.
但如果是运行中的程序,用writeprocessmemory这个函数可能凑效。
运行环境:WIN98+D5
将代码编译好后,把EXE文件拷贝到一张空白的软盘里面,然后从软件里执行这个程序就可以了。
它是用写磁盘绝对位置的方法来修改EXE文件的。
//////////////////////////////
运行时改变自身文件的代码
Here is source code that will create a delphi app that can write to it's own exe file on disk while it runs... win9x only... but you can do the same thing on 95-->xp if you code a different direct sector routine.
It's not magic at all... but it works... Just format a fresh and clean floppy and then compile this code and copy it to the disk... then run it and type in a new DOS stub message in the edit box and press the button... the next time you run the program it will display the DOS stub txt that you entered as it's caption.
This simple minded demo does not look for the sectors that contain your exe because you have placed it on a fresh 1.44 floppy and it know that the dos stub code is in sector 33 :-) but you can code a routine to find all the sectors of an exe on a hd and use the same sort of code to alter all of them...
I worked on a program that downloaded updates from the web and installed them into the running programs exe file... it worked but when I ran it all night doing constant updates on the exe while running a disk defrag it wound up corrupting the hd :-( so I abandoned the scheme in favor of the much safer trick of just appearing to alter an exe's file while it runs....here is the code... I hope the text formats correctlyunit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ComCtrls;type
TForm1 = class(TForm)
Button1: TButton;
Edit1: TEdit;
Label1: TLabel;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
public
end;var
Form1: TForm1;const
VWin32_DIOC_DOS_Int25 = 2; // direct read access
VWin32_DIOC_DOS_Int26 = 3; // direct write accesstype
TDevIoCtl_Reg = packed Record
Reg_EBX : DWord;
Reg_EDX : DWord;
Reg_ECX : DWord;
Reg_EAX : DWord;
Reg_EDI : DWord;
Reg_ESI : DWord;
Reg_Flags : DWord;
end;type
TDiskIO = packed record
StartSektor : DWord;
AnzahlSektoren : Word;
PBuffer : DWord;
end;implementation{$R *.DFM}//Demo program that writes new data to the PE
//of a running delphi exe WHILE IT IS RUNNING! :-)
//To use this demo just freshly format a standard
//1.44 mb floppy disk and then copy this exe to it
//run it from the floppy and it can alter itself
//by writting a new DOS stub Message to the exe's file
//on the disk ... the next time the program is run the
//new stub text will be in the caption :-)
//To do this on a HD just discern the location of the
//disk sector that contains the first 512 bytes of this exe
//you can get this from the dir/fat data... this disk code
//only works on fat 16 hd's so you need to recode for fat32
//This is meant to be a demo that proves that contrary to
//popular opinion an exe can write to it's own file while
//running!... but just because something CAN be done does
//not mean that it SHOULD be done! ... you will likely
//wind up destroying data on a HD if you write code to
//locate an exe on the hd and alter it directly...WinDoze
//is totally blind to the fact that you are writing data
//to the sectors directly and will happily move things about
//while you are doing it... and you will wind up overwritting
//the wrong data sooner or later :-(procedure TForm1.Button1Click(Sender: TObject);
var
x: Integer;
DevIoHandle : THandle;
BytesReturned : DWord;
Reg : TDevIoCtl_Reg;
DiskIO : TDiskIO;
DatenBuffer : Array [0..511] of Byte; // = 512 Bytesbegin
if (length(edit1.text)>35) or (length(edit1.text)=0) then
begin
showmessage('Please enter a new DOS stub text of 1 to 35 chars!');
exit;
end; with DiskIO do
begin
StartSektor := 33; // from sector 33
AnzahlSektoren := 1; // read 1 sector
PBuffer := DWord(@DatenBuffer);
end; with Reg do
begin
Reg_EAX := 0; // drive: 0 = A, 1 = B etc.
Reg_EBX := DWord(@DiskIO);
Reg_ECX := $FFFF; // use DiskIO
end; DevIoHandle := CreateFile(
'\\.\vwin32',
Generic_Read,
File_Share_Read or File_Share_Write,
nil,
Open_Existing,
File_Attribute_Normal,
0); if DevIoHandle <> Invalid_Handle_Value then
begin DeviceIoControl(DevIoHandle,
VWin32_DIOC_DOS_Int25,
@Reg,
SizeOf(Reg),
@Reg,
SizeOf(Reg),
BytesReturned,
nil);
for x := 80 to 80 + length(edit1.text) do
begin
DatenBuffer[x] := ord(edit1.text[x-79]);
end; DeviceIoControl(DevIoHandle,
VWin32_DIOC_DOS_Int26,
@Reg,
SizeOf(Reg),
@Reg,
SizeOf(Reg),
BytesReturned,
nil); CloseHandle(DevIoHandle);
end;
end;procedure TForm1.FormCreate(Sender: TObject);
Var x: Byte;
begin
Form1.Caption := '';
For X := 80 to 115 do
begin
Form1.Caption := Form1.Caption +
Char(pointer(Hinstance+X)^);
end;
end;
end.================
I will zip up a file with all the source files and put it in the attachements group....this will make it easier for anyone that wants to build this silly little demo :-)
p.s.
In the program I wrote to auto-update from the web I was compressing a 500kb delphi app down to 170kb using UPX... then I padded out the compressed file back to the original 500kb using 00H bytes.. this file would then pkzip down to about 160kb because all the 00H's scrunched down
to nearly nothing... this gave me a large space to build out a large update into and let me avoid altering the fat because there was plenty of useable room in the original file...the already allocated sectors were always able to hold a larger updated exe...and all the 00H bytes had no ill effect on the exe before or after an update :-)
writeprocessmemory至少就能够在win95中使用,你可以打开win32 SDK help看看
writeprocessmemory的quick info内容。
这是一个平台无关的函数(NT、9x下都支持)
ring0级才可以使用这个函数。
如果直接用汇编修改地址空间的话只能得到一个GPF。
如果做软件注册用的话,应该是修改EXE文件的啊
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;var
Form1: TForm1;
test:integer;implementation{$R *.dfm}{
使用:按button1,你将得到一个'small'的信息,
按button2修改代码后,按button1将得到'great'
seeking/2001.9.15
win98+delphi6测试通过。
}procedure TForm1.FormCreate(Sender: TObject);
begin
test:=5;
end;//查看效果
procedure TForm1.Button1Click(Sender: TObject);
begin
//下面的判断语句在内存中的代码为$7d1d,汇编语句
//为jnl +$1b ,在未修改时按下按钮将提示samll ,
//修改后就提示great 。
if test<6 then messagebox(handle,'samll','',0) else
messagebox(handle,'great','',0);
end;//修改代码
procedure TForm1.Button2Click(Sender: TObject);
var d,a,l:dword;
begin
l:=$1b7e; //改成$1b7e jle +$1b (即if test>6 then ... )
a:=$0044dc02; //地址,这个地址是可变的。
WriteProcessMemory(getcurrentprocess,//自身进程句柄,如果要写其它进程则
//需要有全权读写的权限,由于是自已
//的空间,当然可以全权读写啦,所以
//直接用这个函数就可以了。
ptr(a), //这是将要写入数据的内存地址,ptr(a)就是将$0044dc02转换成指针
@l, //这是要写入的数据,@l就是取l的地址,等同于addr(l)
2, //写入数据的字节数,这里是2字节
d); //这是函数返回的数据,不用理它
end;
//简单吧,就一个函数搞定。
end.