Note: Take the flower instruction of VC++6 as an example.
//VC++6 Coat 1
OEPCODEFIVE: THEAD =
($55, $8B, $EC, $6A, $FF, $68, $00, $00, $00, $00, $68, $00, $00, $00, $00, $64,
$A1, $00, $00, $00, $00, $50, $64, $89, $25, $00, $00, $00, $00, $83, $EC, $68,
$53, $56, $57, $58, $58, $58, $83, $C4, $68, $58, $67, $64, $A3, $00, $00, $58,
$58, $58, $58, $8B, $E8, $E9, $07, $B9, $FE, $FF, $00, $00, $00, $00, $00, $00);
//VC++6 Coat 2
OEPCODEFIVE: THEAD =
($55, $8B, $EC, $6A, $FF, $68, $00, $00, $00, $00, $68, $00, $00, $00, $00, $64,
$A1, $00, $00, $00, $00, $50, $64, $89, $25, $00, $00, $00, $00, $83, $EC, $68,
$53, $56, $57, $58, $58, $58, $83, $C4, $68, $58, $67, $64, $A3, $00, $00, $58,
$58, $58, $58, $8B, $E8, $B8, $00, $10, $40, $00, $FF, $E0, $90, $00, $00, $00);
1. Directly assign the entry address to the register eax, and then jmp eax
0046902A B8 304A4500 mov eax,Project1.00454A30
0046902F FFE0 jmp eax
00469031 90 nop
2. Jump directly to the entrance address
00469124 - E9 07B9FEFF jmp Project1.00454A30
The two effects are actually the same, but in order to facilitate modification of the flower command, we usually get the original
pe header's AddressOfEntryPoint, and then saves the change value to the register eax, so the second method is not very convenient.
Therefore, the first method is generally adopted. JMPOFF is the offset from the flower instruction code to the jump instruction, such as the flower instruction for Visual C++
JMPOFF=54, the original entrance address is not followed by, you can fill in it at will. The program add-on command will be automatically modified, generally
The default is set to 00104000 (i.e. 00401000).
The statement that modify the flower command to jump to the original entrance address through assembly:
asm //I will explain here that this is embedded assembly code, registers—things that the CPU temporarily stores data, faster than memory to improve efficiency.
PUSHAD
LEA eax, OEPCODE //Talk the address of OEPCODE to the register
ADD eax, JMPOFF //Add JMPOFF value to register
MOV edx, AddressOfEntryPoint //Transfer instruction, equivalent to a value statement, the left side is given to the right side
MOV DWORD ptr [eax], edx //Similar to above
POPAD
end;
}
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls, ShellAPI;
type
TForm1 = class(TForm)
Label1: TLabel;
Edit1: TEdit;
Button1: TButton;
RadioGroup1: TRadioGroup;
Label2: TLabel;
Edit2: TEdit;
Label3: TLabel;
Edit3: TEdit;
CheckBox1: TCheckBox;
Button2: TButton;
Label5: TLabel;
OpenDialog1: TOpenDialog;
Label4: TLabel;
procedure Button1Click(Sender: TObject);
procedure obtain;
procedure Button2Click(Sender: TObject);
procedure Label4Click(Sender: TObject);
procedure Edit3KeyPress(Sender: TObject; var Key: Char);
private
{ Private declarations }
FImageBase: DWORD;
procedure SetOepCode;
public
{ Public declarations }
end;
THEAD = array[0..63] of byte;
var
Form1: TForm1;
const
{MYSECTION= 'Fi7ke'; //Added section name, custom
JMPOFF = 43; //The machine code of the instruction is fetched casually after Ollydbg loads.
//Microsoft Visual C++
OEPCODE: THEAD =
($55, $8B, $EC, $6A, $FF, $68, $2A, $2C, $0A, $00, $68, $38,
$90, $0D, $00, $64, $A1, $00, $00, $00, $00, $50, $64, $89,
$25, $00, $00, $00, $00, $58, $64, $A3, $00, $00, $00, $00,
$58, $58, $58, $58, $8B, $E8, $B8, $00, $10, $40, $00, $FF,
$E0, $90, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00,
$00, $00, $00, $00); }
//Nothing found * one
OEPCODEONE: THEAD =
($55, $8B, $EC, $83, $C4, $F4, $83, $C4, $0C, $B8, $00, $10, $40, $00, $50, $C3,
$00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00,
$00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00,
$00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00);
//Nothing found * two
OEPCODETWO: THEAD =
($55, $8B, $EC, $41, $52, $90, $5A, $49, $5D, $41, $B8, $00, $10, $40, $00, $FF,
$E0, $90, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00,
$00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00,
$00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00);
//VC++ coat
OEPCODETHREE: THEAD =
($55, $8B, $EC, $6A, $FF, $68, $2A, $2C, $0A, $00, $68, $38, $90, $0D, $00, $64,
$A1, $00, $00, $00, $00, $50, $64, $89, $25, $00, $00, $00, $00, $58, $64, $A3,
$00, $00, $00, $00, $58, $58, $58, $58, $8B, $E8, $B8, $00, $10, $40, $00, $FF,
$E0, $90, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00);
//VC++5 outerwear
OEPCODEFOUR: THEAD =
($55, $8B, $EC, $6A, $FF, $68, $48, $54, $41, $00, $68, $A8, $21, $40, $00, $64,
$A1, $00, $00, $00, $00, $50, $64, $89, $25, $00, $00, $00, $00, $83, $C4, $94,
$53, $56, $57, $00, $00, $B8, $00, $10, $40, $00, $FF, $E0, $90, $00, $00, $00,
$00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00);
//VC++6 outerwear
OEPCODEFIVE: THEAD =
($55, $8B, $EC, $6A, $FF, $68, $00, $00, $00, $00, $68, $00, $00, $00, $00, $64,
$A1, $00, $00, $00, $00, $50, $64, $89, $25, $00, $00, $00, $00, $83, $EC, $68,
$53, $56, $57, $58, $58, $58, $83, $C4, $68, $58, $67, $64, $A3, $00, $00, $58,
$58, $58, $58, $8B, $E8, $B8, $00, $10, $40, $00, $FF, $E0, $90, $00, $00, $00);
//C Coat
OEPCODESIX: THEAD =
($55, $8B, $EC, $6A, $FF, $68, $11, $11, $11, $00, $68, $22, $22, $22, $00, $64,
$A1, $00, $00, $00, $00, $50, $64, $89, $25, $00, $00, $00, $00, $58, $64, $A3,
$00, $00, $00, $00, $58, $58, $58, $58, $8B, $E8, $B8, $00, $10, $40, $00, $FF,
$E0, $90, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00);
OepCount = 6;
//OEPCODEARRAY :array[0..OepCount-1,0..63] of byte=(
//OEPCODEARRAY :array[0..OepCount-1] of array[0..63] of byte=(
OEPCODEARRAY :array[0..OepCount-1] of THEAD=(
($55, $8B, $EC, $83, $C4, $F4, $83, $C4, $0C, $B8, $00, $10, $40, $00, $50, $C3,
$00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00,
$00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00,
$00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00), //Nothing found * one
($55, $8B, $EC, $6A, $FF, $68, $2A, $2C, $0A, $00, $68, $38, $90, $0D, $00, $64,
$A1, $00, $00, $00, $00, $50, $64, $89, $25, $00, $00, $00, $00, $58, $64, $A3,
$00, $00, $00, $00, $58, $58, $58, $58, $8B, $E8, $B8, $00, $10, $40, $00, $FF,
$E0, $90, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00), //VC++ Coat
($55, $8B, $EC, $6A, $FF, $68, $48, $54, $41, $00, $68, $A8, $21, $40, $00, $64,
$A1, $00, $00, $00, $00, $50, $64, $89, $25, $00, $00, $00, $00, $83, $C4, $94,
$53, $56, $57, $00, $00, $B8, $00, $10, $40, $00, $FF, $E0, $90, $00, $00, $00,
$00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00), //VC++5 outerwear
($55, $8B, $EC, $6A, $FF, $68, $00, $00, $00, $00, $68, $00, $00, $00, $00, $64,
$A1, $00, $00, $00, $00, $50, $64, $89, $25, $00, $00, $00, $00, $83, $EC, $68,
$53, $56, $57, $58, $58, $58, $83, $C4, $68, $58, $67, $64, $A3, $00, $00, $58,
$58, $58, $58, $8B, $E8, $B8, $00, $10, $40, $00, $FF, $E0, $90, $00, $00, $00), //VC++6 outerwear
($55, $8B, $EC, $6A, $FF, $68, $11, $11, $11, $00, $68, $22, $22, $22, $00, $64,
$A1, $00, $00, $00, $00, $50, $64, $89, $25, $00, $00, $00, $00, $58, $64, $A3,
$00, $00, $00, $00, $58, $58, $58, $58, $8B, $E8, $B8, $00, $10, $40, $00, $FF,
$E0, $90, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00), //C Coat
($55, $8B, $EC, $41, $52, $90, $5A, $49, $5D, $41, $B8, $00, $10, $40, $00, $FF,
$E0, $90, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00,
$00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00,
$00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00) //Nothing found * two
);
JMPOFFARRAY :array[0..OepCount-1] of integer=(10,43,38,54,43,11);
{Nothing found * ONE:
Borland Delphi 6.0 - 7.0
00469022 0055 8B add byte ptr ss:[ebp-75],dl
00469025 EC in al,dx
00469026 83C4 F4 add esp,-0C
00469029 83C4 0C add esp,0C
0046902C B8 304A4500 mov eax,Project1.00454A30
00469031 50 push eax
00469032 C3 retn
Nothing found * TWO
00454A72 55 push ebp
00454A73 8BEC mov ebp,esp
00454A75 41 inc ecx
00454A76 52 push edx
00454A77 90 nop
00454A78 5A pop edx
00454A79 49 dec ecx
00454A7A 5D pop ebp
00454A7B 41 inc ecx
0046902A B8 304A4500 mov eax,Project1.00454A30
0046902F FFE0 jmp eax
00469031 90 nop
C outerwear:
00454A6C 55 push ebp
00454A6D 8BEC mov ebp,esp
00454A6F 6A FF push -1
00454A71 68 11111100 push 111111
00454A76 68 22222200 push 222222
00454A7B 64:A1 00000>mov eax,dword ptr fs:[0]
00454A81 50 push eax
00454A82 64:8925 000>mov dword ptr fs:[0],esp
00454A89 58 pop eax
00454A8A 64:A3 00000>mov dword ptr fs:[0],eax
00454A90 58 pop eax
00454A91 58 pop eax
00454A92 58 pop eax
00454A93 58 pop eax
00454A94 8BE8 mov ebp,eax
00454A96 - E9 65F5CAFF jmp 00104000
VC++5 outerwear:
0046905F P> 55 push ebp
00469060 8BEC mov ebp,esp
00469062 6A FF push -1
00469064 68 48544100 push Project1.00415448
00469069 68 A8214000 push Project1.004021A8
0046906E 64:A1 0000000>mov eax,dword ptr fs:[0]
00469074 50 push eax
00469075 64:8925 00000>mov dword ptr fs:[0],esp
0046907C 83C4 94 add esp,-6C
0046907F 53 push ebx
00469080 56 push esi
00469081 57 push edi
00469082 0000 add byte ptr ds:[eax],al
0046902A B8 304A4500 mov eax,Project1.00454A30
0046902F FFE0 jmp eax
00469031 90 nop
VC++ coat:
00469000 P> 55 push ebp
00469001 8BEC mov ebp,esp
00469003 6A FF push -1
00469005 68 2A2C0A00 push 0A2C2A
0046900A 68 38900D00 push 0D9038
0046900F 64:A1 0000000>mov eax,dword ptr fs:[0]
00469015 50 push eax
00469016 64:8925 00000>mov dword ptr fs:[0],esp
0046901D 58 pop eax
0046901E 64:A3 0000000>mov dword ptr fs:[0],eax
00469024 58 pop eax
00469025 58 pop eax
00469026 58 pop eax
00469027 58 pop eax
00469028 8BE8 mov ebp,eax
0046902A B8 304A4500 mov eax,Project1.00454A30
0046902F FFE0 jmp eax
00469031 90 nop
VC++6 outerwear:
004690EF P> 55 push ebp
004690F0 8BEC mov ebp,esp
004690F2 6A FF push -1
004690F4 68 00000000 push 0
004690F9 68 00000000 push 0
004690FE 64:A1 0000000>mov eax,dword ptr fs:[0]
00469104 50 push eax
00469105 64:8925 00000>mov dword ptr fs:[0],esp
0046910C 83EC 68 sub esp,68
0046910F 53 push ebx
00469110 56 push esi
00469111 57 push edi
00469112 58 pop eax
00469113 58 pop eax
00469114 58 pop eax
00469115 83C4 68 add esp,68
00469118 58 pop eax
00469119 67:64:A3 0000 mov dword ptr fs:[0],eax
0046911E 58 pop eax
0046911F 58 pop eax
00469120 58 pop eax
00469121 58 pop eax
00469122 8BE8 mov ebp,eax
0046902A B8 304A4500 mov eax,Project1.00454A30
0046902F FFE0 jmp eax
00469031 90 nop
}
function IntToHex(Int: Int64; IntSize: Byte): String;
procedure AddSection(FName,MySection: string;SecSize:DWord);
implementation
{$R *.dfm}
var
OEPCODE: THEAD;
JMPOFF :integer;
function IntToHex(Int: Int64; IntSize: Byte): String;
const
HexChars: array[0..15] of Char = ('0', '1', '2', '3', '4', '5','6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f');
var
n: Byte;
begin
Result := '';
for n := 0 to IntSize - 1 do
begin
Result := HexChars[Int and $F] + Result;
Int := Int shr $4;
end;
end;
procedure AddSection(FName,MySection: string;SecSize:DWord);
var
DOSHEADER: IMAGE_DOS_HEADER; //DOS MZ header
PEHEADER: IMAGE_NT_HEADERS; //PE header
SectionHeader: IMAGE_SECTION_HEADER; //Section table
MySectionHeader: IMAGE_SECTION_HEADER; //Custom section table
fs: TFileStream;
AddressOfEntryPoint: DWORD; //Entry Point
i:integer;
begin
fs := (FName, fmOpenReadWrite +
fmShareDenyWrite);
try
{There are four virtual methods defined in Tstream:
1. Read: This method realizes reading data from the stream. The function prototype is:
Function Read(var Buffer;Count:Longint):Longint;virtual;abstract;
The parameter Buffer is the buffer placed when data is read out, and Count is the number of bytes of the data to be read out. The return value of this method is the actual number of bytes read out, which can be less than or equal to the value specified in Count.
2. Write: This method implements writing data into the stream. The function prototype is:
Function Write(var Buffer;Count:Longint):Longint;virtual;abstract;
The parameter Buffer is the buffer of the data to be written to the stream, and Count is the number of bytes of the length of the data. The return value of this method is the number of bytes actually written to the stream.
3. Seek: This method realizes the movement of the read pointer in the stream. The function prototype is:
Function Seek(Offset:Longint;Origint:Word):Longint;virtual;abstract;
The parameter Offset is the number of offset bytes. The parameter Origin points out the actual significance of Offset. The possible values are as follows:
soFromBeginning:Offset is the position where the pointer distance data starts after movement. At this time, Offset must be greater than or equal to zero.
soFromCurrent:Offset is the relative position of the pointer and the current pointer after moving.
soFromEnd:Offset is the position where the pointer distance data ends after movement. At this time, Offset must be less than or equal to zero. The return value of this method is the position of the pointer after moving.
4. Setsize: This method realizes changing the size of the data. The function prototype is:
Function Setsize(NewSize:Longint);virtual; }
//Put the pointer offset to the head of the file
(0, soFromBeginning);
//Read DOS header information
(DOSHEADER, sizeof(DOSHEADER));
//DOS MZ header is also named IMAGE_DOS_HEADER. Only two domains are more important:
//e_magic contains the string "MZ", and e_lfanew contains the offset of PE header in the file.
//Move the pointer to the offset of PE header in the file
(DOSHEADER._lfanew, soFromBeginning);
//Read PE header header information
(PEHEADER, sizeOf(PEHEADER));
//: Number of sections of the file. If we want to add or delete a section in the file, we need to modify this value.
//Move the pointer to the relative offset of the section table at its current position
(sizeOf(SectionHeader) *
( - 1), soFromCurrent);
//Read information of section table
(SectionHeader, sizeof(IMAGE_SECTION_HEADER));
//The length of the section is no more than 8 bytes. Remember that the name of a festival is just a mark, we can choose any name or even be empty.
{ [0] := ord('F');
[1] := ord('i');
[2] := ord('7');
[3] := ord('k');
[4] := ord('e');
[5] := 0;
[6] := 0;
[7] := 0; }
for i:=0 to 7 do
begin
[i] :=0;
if i<length(MySection) then
[i] :=Ord(MySection[i+1]);
end;
//VirtualAddress The RVA (relative virtual address) of this section. This value is read when the PE loader maps a section to memory, so if the domain value is 1000h,
//If the PE file is loaded at address 400000h, then this section will be loaded to 401000h.
//SizeOfImage The size of the entire PE image body in memory. It is the size of all headers and sections after being segmentally aligned.
:= ;
//The size of the section $200 hexadecimal = 512 bytes It is best to be larger than 512, otherwise there may be an error
// := $200;
:= SecSize; //StrToInt(IntToHex(SecSize,sizeof(SecSize)));
//SizeOfRawData After file alignment, the section size is processed. The PE loader extracts the value of this field to understand the number of bytes to be mapped into the memory.
// (Translator's note: Assume that the file alignment size of a file is 0x200, if the preceding VirtualSize field indicates that the length of this section is 0x388 bytes,
//The value of this field is 0x400, indicating that this section is 0x400 bytes long).
//FileAlignment The granularity of section alignment in the file. For example, if the value is (200h), then the starting address of each section must be a multiple of 512.
//If the first section starts from the file offset 200h and the size is 10 bytes, the next section must be at the offset 400h:
//Even if there is still a lot of space between offsets 512 and 1024 that is not used/defined.
:= ( div
+ 1) * -
;
//This is the offset of the section based on the file. The PE loader finds the location of the section data in the file through the value of this field.
:=
+ ;
//Include tags to indicate section attributes, such as whether the section contains executable code, initialized data, uninitial data, whether it is writable, readable, etc.
:= $E0000020;
{PE loader work:
1. Read the NumberOfSections field of IMAGE_FILE_HEADER to know the number of sections of the file.
The field value is used as the file offset of the section table, and the section table is located using this.
3. Traverse the entire structure array and check the values of each member.
4. For each structure, we read the PointerToRawData field value and locate the file offset. Then read the SizeOfRawData field value to decide
The number of bytes in the mapped memory. Add the VirtualAddress field value plus the ImageBase field value equals the virtual address at the beginning of the section. Then I'm going to map the section into memory.
And set properties according to the Characteristics field value.
5. Iterate through the entire array until all sections have been processed.
Note that we do not use the section name: This is actually not important. }
//Add one section number
Inc();
//Write to newly added section table
(MySectionHeader, sizeOf(MySectionHeader));
//Move the pointer to the offset of PE header in the file
(DOSHEADER._lfanew, soFromBeginning);
//PE loader prepares RVA for the first instruction of the PE file to run. If you want to change the entire execution process,
//This value can be specified to the new RVA, so that the instructions at the new RVA are executed first.
AddressOfEntryPoint := ;
//Specify the entry address to the RVA (relative virtual address) of the newly added section table
:=
;
//win32 subsystem version.
:= 7;
:= 0;
AddressOfEntryPoint := AddressOfEntryPoint +
;
asm // Let me explain here that this is embedded assembly code, registers—the thing that the CPU temporarily stores data, faster than memory to improve efficiency.
PUSHAD
LEA eax, OEPCODE //Talk the address of OEPCODE to the register
ADD eax, JMPOFF //Add JMPOFF value to register
MOV edx, AddressOfEntryPoint //Transfer instruction, equivalent to a value statement, the left side is given to the right side
MOV DWORD ptr [eax], edx //Similar to
POPAD
end;
//Change the size of the entire PE image body in memory
:=
+ ;
//Write PEHEADER information
(PEHEADER, sizeof(PEHEADER));
//Move the pointer to the end of the file
(, soFromBeginning);
//Write flower instruction data
(OEPCODE, );
finally
;
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
if then
:=;
end;
procedure ;
var
DOSHEADER: IMAGE_DOS_HEADER;
PEHEADER: IMAGE_NT_HEADERS;
fs: TFileStream;
begin
fs := (, fmOpenReadWrite +
fmShareDenyWrite);
try
(0, soFromBeginning);
(DOSHEADER, sizeof(DOSHEADER));
(DOSHEADER._lfanew, soFromBeginning);
(PEHEADER, sizeOf(PEHEADER));
FImageBase := ;
finally
;
end;
end;
procedure TForm1.Button2Click(Sender: TObject);
var
FName,SecName:string;
SecSize:DWord;
begin
if trim() = '' then
begin
Messagebox(Handle, 'Please select the program you want to disguise!', 'Tip', MB_OK + MB_ICONSTOP);
Exit;
end;
FName :=trim();
SecName :=trim();
if SecName='' then SecName:='.hnxyy';
SecSize :=512;
if trim()<>'' then
begin
SecSize :=strtoint(trim());
if SecSize<512 then SecSize :=512;
end;
if then
CopyFile(PChar(FName),PChar(Fname+'.bak'),False);
SetOepCode;
AddSection(FName,SecName,SecSize);
Messagebox(Handle, 'Disguise Successfully!', 'Tip', MB_OK + MB_ICONINFORMATION);
end;
procedure ;
begin
OEPCODE :=OEPCODEARRAY[];
JMPOFF :=JMPOFFARRAY[];
end;
procedure TForm1.Label4Click(Sender: TObject);
begin
ShellExecute(Handle, 'open','', '', '', SW_SHOWNORMAL);
end;
procedure TForm1.Edit3KeyPress(Sender: TObject; var Key: Char);
begin
if not (key in ['0'..'9',#8,#13]) then
begin
key :=#0;
end;
end;
end.
//VC++6 Coat 1
OEPCODEFIVE: THEAD =
($55, $8B, $EC, $6A, $FF, $68, $00, $00, $00, $00, $68, $00, $00, $00, $00, $64,
$A1, $00, $00, $00, $00, $50, $64, $89, $25, $00, $00, $00, $00, $83, $EC, $68,
$53, $56, $57, $58, $58, $58, $83, $C4, $68, $58, $67, $64, $A3, $00, $00, $58,
$58, $58, $58, $8B, $E8, $E9, $07, $B9, $FE, $FF, $00, $00, $00, $00, $00, $00);
//VC++6 Coat 2
OEPCODEFIVE: THEAD =
($55, $8B, $EC, $6A, $FF, $68, $00, $00, $00, $00, $68, $00, $00, $00, $00, $64,
$A1, $00, $00, $00, $00, $50, $64, $89, $25, $00, $00, $00, $00, $83, $EC, $68,
$53, $56, $57, $58, $58, $58, $83, $C4, $68, $58, $67, $64, $A3, $00, $00, $58,
$58, $58, $58, $8B, $E8, $B8, $00, $10, $40, $00, $FF, $E0, $90, $00, $00, $00);
1. Directly assign the entry address to the register eax, and then jmp eax
0046902A B8 304A4500 mov eax,Project1.00454A30
0046902F FFE0 jmp eax
00469031 90 nop
2. Jump directly to the entrance address
00469124 - E9 07B9FEFF jmp Project1.00454A30
The two effects are actually the same, but in order to facilitate modification of the flower command, we usually get the original
pe header's AddressOfEntryPoint, and then saves the change value to the register eax, so the second method is not very convenient.
Therefore, the first method is generally adopted. JMPOFF is the offset from the flower instruction code to the jump instruction, such as the flower instruction for Visual C++
JMPOFF=54, the original entrance address is not followed by, you can fill in it at will. The program add-on command will be automatically modified, generally
The default is set to 00104000 (i.e. 00401000).
The statement that modify the flower command to jump to the original entrance address through assembly:
asm //I will explain here that this is embedded assembly code, registers—things that the CPU temporarily stores data, faster than memory to improve efficiency.
PUSHAD
LEA eax, OEPCODE //Talk the address of OEPCODE to the register
ADD eax, JMPOFF //Add JMPOFF value to register
MOV edx, AddressOfEntryPoint //Transfer instruction, equivalent to a value statement, the left side is given to the right side
MOV DWORD ptr [eax], edx //Similar to above
POPAD
end;
}
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls, ShellAPI;
type
TForm1 = class(TForm)
Label1: TLabel;
Edit1: TEdit;
Button1: TButton;
RadioGroup1: TRadioGroup;
Label2: TLabel;
Edit2: TEdit;
Label3: TLabel;
Edit3: TEdit;
CheckBox1: TCheckBox;
Button2: TButton;
Label5: TLabel;
OpenDialog1: TOpenDialog;
Label4: TLabel;
procedure Button1Click(Sender: TObject);
procedure obtain;
procedure Button2Click(Sender: TObject);
procedure Label4Click(Sender: TObject);
procedure Edit3KeyPress(Sender: TObject; var Key: Char);
private
{ Private declarations }
FImageBase: DWORD;
procedure SetOepCode;
public
{ Public declarations }
end;
THEAD = array[0..63] of byte;
var
Form1: TForm1;
const
{MYSECTION= 'Fi7ke'; //Added section name, custom
JMPOFF = 43; //The machine code of the instruction is fetched casually after Ollydbg loads.
//Microsoft Visual C++
OEPCODE: THEAD =
($55, $8B, $EC, $6A, $FF, $68, $2A, $2C, $0A, $00, $68, $38,
$90, $0D, $00, $64, $A1, $00, $00, $00, $00, $50, $64, $89,
$25, $00, $00, $00, $00, $58, $64, $A3, $00, $00, $00, $00,
$58, $58, $58, $58, $8B, $E8, $B8, $00, $10, $40, $00, $FF,
$E0, $90, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00,
$00, $00, $00, $00); }
//Nothing found * one
OEPCODEONE: THEAD =
($55, $8B, $EC, $83, $C4, $F4, $83, $C4, $0C, $B8, $00, $10, $40, $00, $50, $C3,
$00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00,
$00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00,
$00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00);
//Nothing found * two
OEPCODETWO: THEAD =
($55, $8B, $EC, $41, $52, $90, $5A, $49, $5D, $41, $B8, $00, $10, $40, $00, $FF,
$E0, $90, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00,
$00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00,
$00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00);
//VC++ coat
OEPCODETHREE: THEAD =
($55, $8B, $EC, $6A, $FF, $68, $2A, $2C, $0A, $00, $68, $38, $90, $0D, $00, $64,
$A1, $00, $00, $00, $00, $50, $64, $89, $25, $00, $00, $00, $00, $58, $64, $A3,
$00, $00, $00, $00, $58, $58, $58, $58, $8B, $E8, $B8, $00, $10, $40, $00, $FF,
$E0, $90, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00);
//VC++5 outerwear
OEPCODEFOUR: THEAD =
($55, $8B, $EC, $6A, $FF, $68, $48, $54, $41, $00, $68, $A8, $21, $40, $00, $64,
$A1, $00, $00, $00, $00, $50, $64, $89, $25, $00, $00, $00, $00, $83, $C4, $94,
$53, $56, $57, $00, $00, $B8, $00, $10, $40, $00, $FF, $E0, $90, $00, $00, $00,
$00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00);
//VC++6 outerwear
OEPCODEFIVE: THEAD =
($55, $8B, $EC, $6A, $FF, $68, $00, $00, $00, $00, $68, $00, $00, $00, $00, $64,
$A1, $00, $00, $00, $00, $50, $64, $89, $25, $00, $00, $00, $00, $83, $EC, $68,
$53, $56, $57, $58, $58, $58, $83, $C4, $68, $58, $67, $64, $A3, $00, $00, $58,
$58, $58, $58, $8B, $E8, $B8, $00, $10, $40, $00, $FF, $E0, $90, $00, $00, $00);
//C Coat
OEPCODESIX: THEAD =
($55, $8B, $EC, $6A, $FF, $68, $11, $11, $11, $00, $68, $22, $22, $22, $00, $64,
$A1, $00, $00, $00, $00, $50, $64, $89, $25, $00, $00, $00, $00, $58, $64, $A3,
$00, $00, $00, $00, $58, $58, $58, $58, $8B, $E8, $B8, $00, $10, $40, $00, $FF,
$E0, $90, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00);
OepCount = 6;
//OEPCODEARRAY :array[0..OepCount-1,0..63] of byte=(
//OEPCODEARRAY :array[0..OepCount-1] of array[0..63] of byte=(
OEPCODEARRAY :array[0..OepCount-1] of THEAD=(
($55, $8B, $EC, $83, $C4, $F4, $83, $C4, $0C, $B8, $00, $10, $40, $00, $50, $C3,
$00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00,
$00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00,
$00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00), //Nothing found * one
($55, $8B, $EC, $6A, $FF, $68, $2A, $2C, $0A, $00, $68, $38, $90, $0D, $00, $64,
$A1, $00, $00, $00, $00, $50, $64, $89, $25, $00, $00, $00, $00, $58, $64, $A3,
$00, $00, $00, $00, $58, $58, $58, $58, $8B, $E8, $B8, $00, $10, $40, $00, $FF,
$E0, $90, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00), //VC++ Coat
($55, $8B, $EC, $6A, $FF, $68, $48, $54, $41, $00, $68, $A8, $21, $40, $00, $64,
$A1, $00, $00, $00, $00, $50, $64, $89, $25, $00, $00, $00, $00, $83, $C4, $94,
$53, $56, $57, $00, $00, $B8, $00, $10, $40, $00, $FF, $E0, $90, $00, $00, $00,
$00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00), //VC++5 outerwear
($55, $8B, $EC, $6A, $FF, $68, $00, $00, $00, $00, $68, $00, $00, $00, $00, $64,
$A1, $00, $00, $00, $00, $50, $64, $89, $25, $00, $00, $00, $00, $83, $EC, $68,
$53, $56, $57, $58, $58, $58, $83, $C4, $68, $58, $67, $64, $A3, $00, $00, $58,
$58, $58, $58, $8B, $E8, $B8, $00, $10, $40, $00, $FF, $E0, $90, $00, $00, $00), //VC++6 outerwear
($55, $8B, $EC, $6A, $FF, $68, $11, $11, $11, $00, $68, $22, $22, $22, $00, $64,
$A1, $00, $00, $00, $00, $50, $64, $89, $25, $00, $00, $00, $00, $58, $64, $A3,
$00, $00, $00, $00, $58, $58, $58, $58, $8B, $E8, $B8, $00, $10, $40, $00, $FF,
$E0, $90, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00), //C Coat
($55, $8B, $EC, $41, $52, $90, $5A, $49, $5D, $41, $B8, $00, $10, $40, $00, $FF,
$E0, $90, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00,
$00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00,
$00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00) //Nothing found * two
);
JMPOFFARRAY :array[0..OepCount-1] of integer=(10,43,38,54,43,11);
{Nothing found * ONE:
Borland Delphi 6.0 - 7.0
00469022 0055 8B add byte ptr ss:[ebp-75],dl
00469025 EC in al,dx
00469026 83C4 F4 add esp,-0C
00469029 83C4 0C add esp,0C
0046902C B8 304A4500 mov eax,Project1.00454A30
00469031 50 push eax
00469032 C3 retn
Nothing found * TWO
00454A72 55 push ebp
00454A73 8BEC mov ebp,esp
00454A75 41 inc ecx
00454A76 52 push edx
00454A77 90 nop
00454A78 5A pop edx
00454A79 49 dec ecx
00454A7A 5D pop ebp
00454A7B 41 inc ecx
0046902A B8 304A4500 mov eax,Project1.00454A30
0046902F FFE0 jmp eax
00469031 90 nop
C outerwear:
00454A6C 55 push ebp
00454A6D 8BEC mov ebp,esp
00454A6F 6A FF push -1
00454A71 68 11111100 push 111111
00454A76 68 22222200 push 222222
00454A7B 64:A1 00000>mov eax,dword ptr fs:[0]
00454A81 50 push eax
00454A82 64:8925 000>mov dword ptr fs:[0],esp
00454A89 58 pop eax
00454A8A 64:A3 00000>mov dword ptr fs:[0],eax
00454A90 58 pop eax
00454A91 58 pop eax
00454A92 58 pop eax
00454A93 58 pop eax
00454A94 8BE8 mov ebp,eax
00454A96 - E9 65F5CAFF jmp 00104000
VC++5 outerwear:
0046905F P> 55 push ebp
00469060 8BEC mov ebp,esp
00469062 6A FF push -1
00469064 68 48544100 push Project1.00415448
00469069 68 A8214000 push Project1.004021A8
0046906E 64:A1 0000000>mov eax,dword ptr fs:[0]
00469074 50 push eax
00469075 64:8925 00000>mov dword ptr fs:[0],esp
0046907C 83C4 94 add esp,-6C
0046907F 53 push ebx
00469080 56 push esi
00469081 57 push edi
00469082 0000 add byte ptr ds:[eax],al
0046902A B8 304A4500 mov eax,Project1.00454A30
0046902F FFE0 jmp eax
00469031 90 nop
VC++ coat:
00469000 P> 55 push ebp
00469001 8BEC mov ebp,esp
00469003 6A FF push -1
00469005 68 2A2C0A00 push 0A2C2A
0046900A 68 38900D00 push 0D9038
0046900F 64:A1 0000000>mov eax,dword ptr fs:[0]
00469015 50 push eax
00469016 64:8925 00000>mov dword ptr fs:[0],esp
0046901D 58 pop eax
0046901E 64:A3 0000000>mov dword ptr fs:[0],eax
00469024 58 pop eax
00469025 58 pop eax
00469026 58 pop eax
00469027 58 pop eax
00469028 8BE8 mov ebp,eax
0046902A B8 304A4500 mov eax,Project1.00454A30
0046902F FFE0 jmp eax
00469031 90 nop
VC++6 outerwear:
004690EF P> 55 push ebp
004690F0 8BEC mov ebp,esp
004690F2 6A FF push -1
004690F4 68 00000000 push 0
004690F9 68 00000000 push 0
004690FE 64:A1 0000000>mov eax,dword ptr fs:[0]
00469104 50 push eax
00469105 64:8925 00000>mov dword ptr fs:[0],esp
0046910C 83EC 68 sub esp,68
0046910F 53 push ebx
00469110 56 push esi
00469111 57 push edi
00469112 58 pop eax
00469113 58 pop eax
00469114 58 pop eax
00469115 83C4 68 add esp,68
00469118 58 pop eax
00469119 67:64:A3 0000 mov dword ptr fs:[0],eax
0046911E 58 pop eax
0046911F 58 pop eax
00469120 58 pop eax
00469121 58 pop eax
00469122 8BE8 mov ebp,eax
0046902A B8 304A4500 mov eax,Project1.00454A30
0046902F FFE0 jmp eax
00469031 90 nop
}
function IntToHex(Int: Int64; IntSize: Byte): String;
procedure AddSection(FName,MySection: string;SecSize:DWord);
implementation
{$R *.dfm}
var
OEPCODE: THEAD;
JMPOFF :integer;
function IntToHex(Int: Int64; IntSize: Byte): String;
const
HexChars: array[0..15] of Char = ('0', '1', '2', '3', '4', '5','6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f');
var
n: Byte;
begin
Result := '';
for n := 0 to IntSize - 1 do
begin
Result := HexChars[Int and $F] + Result;
Int := Int shr $4;
end;
end;
procedure AddSection(FName,MySection: string;SecSize:DWord);
var
DOSHEADER: IMAGE_DOS_HEADER; //DOS MZ header
PEHEADER: IMAGE_NT_HEADERS; //PE header
SectionHeader: IMAGE_SECTION_HEADER; //Section table
MySectionHeader: IMAGE_SECTION_HEADER; //Custom section table
fs: TFileStream;
AddressOfEntryPoint: DWORD; //Entry Point
i:integer;
begin
fs := (FName, fmOpenReadWrite +
fmShareDenyWrite);
try
{There are four virtual methods defined in Tstream:
1. Read: This method realizes reading data from the stream. The function prototype is:
Function Read(var Buffer;Count:Longint):Longint;virtual;abstract;
The parameter Buffer is the buffer placed when data is read out, and Count is the number of bytes of the data to be read out. The return value of this method is the actual number of bytes read out, which can be less than or equal to the value specified in Count.
2. Write: This method implements writing data into the stream. The function prototype is:
Function Write(var Buffer;Count:Longint):Longint;virtual;abstract;
The parameter Buffer is the buffer of the data to be written to the stream, and Count is the number of bytes of the length of the data. The return value of this method is the number of bytes actually written to the stream.
3. Seek: This method realizes the movement of the read pointer in the stream. The function prototype is:
Function Seek(Offset:Longint;Origint:Word):Longint;virtual;abstract;
The parameter Offset is the number of offset bytes. The parameter Origin points out the actual significance of Offset. The possible values are as follows:
soFromBeginning:Offset is the position where the pointer distance data starts after movement. At this time, Offset must be greater than or equal to zero.
soFromCurrent:Offset is the relative position of the pointer and the current pointer after moving.
soFromEnd:Offset is the position where the pointer distance data ends after movement. At this time, Offset must be less than or equal to zero. The return value of this method is the position of the pointer after moving.
4. Setsize: This method realizes changing the size of the data. The function prototype is:
Function Setsize(NewSize:Longint);virtual; }
//Put the pointer offset to the head of the file
(0, soFromBeginning);
//Read DOS header information
(DOSHEADER, sizeof(DOSHEADER));
//DOS MZ header is also named IMAGE_DOS_HEADER. Only two domains are more important:
//e_magic contains the string "MZ", and e_lfanew contains the offset of PE header in the file.
//Move the pointer to the offset of PE header in the file
(DOSHEADER._lfanew, soFromBeginning);
//Read PE header header information
(PEHEADER, sizeOf(PEHEADER));
//: Number of sections of the file. If we want to add or delete a section in the file, we need to modify this value.
//Move the pointer to the relative offset of the section table at its current position
(sizeOf(SectionHeader) *
( - 1), soFromCurrent);
//Read information of section table
(SectionHeader, sizeof(IMAGE_SECTION_HEADER));
//The length of the section is no more than 8 bytes. Remember that the name of a festival is just a mark, we can choose any name or even be empty.
{ [0] := ord('F');
[1] := ord('i');
[2] := ord('7');
[3] := ord('k');
[4] := ord('e');
[5] := 0;
[6] := 0;
[7] := 0; }
for i:=0 to 7 do
begin
[i] :=0;
if i<length(MySection) then
[i] :=Ord(MySection[i+1]);
end;
//VirtualAddress The RVA (relative virtual address) of this section. This value is read when the PE loader maps a section to memory, so if the domain value is 1000h,
//If the PE file is loaded at address 400000h, then this section will be loaded to 401000h.
//SizeOfImage The size of the entire PE image body in memory. It is the size of all headers and sections after being segmentally aligned.
:= ;
//The size of the section $200 hexadecimal = 512 bytes It is best to be larger than 512, otherwise there may be an error
// := $200;
:= SecSize; //StrToInt(IntToHex(SecSize,sizeof(SecSize)));
//SizeOfRawData After file alignment, the section size is processed. The PE loader extracts the value of this field to understand the number of bytes to be mapped into the memory.
// (Translator's note: Assume that the file alignment size of a file is 0x200, if the preceding VirtualSize field indicates that the length of this section is 0x388 bytes,
//The value of this field is 0x400, indicating that this section is 0x400 bytes long).
//FileAlignment The granularity of section alignment in the file. For example, if the value is (200h), then the starting address of each section must be a multiple of 512.
//If the first section starts from the file offset 200h and the size is 10 bytes, the next section must be at the offset 400h:
//Even if there is still a lot of space between offsets 512 and 1024 that is not used/defined.
:= ( div
+ 1) * -
;
//This is the offset of the section based on the file. The PE loader finds the location of the section data in the file through the value of this field.
:=
+ ;
//Include tags to indicate section attributes, such as whether the section contains executable code, initialized data, uninitial data, whether it is writable, readable, etc.
:= $E0000020;
{PE loader work:
1. Read the NumberOfSections field of IMAGE_FILE_HEADER to know the number of sections of the file.
The field value is used as the file offset of the section table, and the section table is located using this.
3. Traverse the entire structure array and check the values of each member.
4. For each structure, we read the PointerToRawData field value and locate the file offset. Then read the SizeOfRawData field value to decide
The number of bytes in the mapped memory. Add the VirtualAddress field value plus the ImageBase field value equals the virtual address at the beginning of the section. Then I'm going to map the section into memory.
And set properties according to the Characteristics field value.
5. Iterate through the entire array until all sections have been processed.
Note that we do not use the section name: This is actually not important. }
//Add one section number
Inc();
//Write to newly added section table
(MySectionHeader, sizeOf(MySectionHeader));
//Move the pointer to the offset of PE header in the file
(DOSHEADER._lfanew, soFromBeginning);
//PE loader prepares RVA for the first instruction of the PE file to run. If you want to change the entire execution process,
//This value can be specified to the new RVA, so that the instructions at the new RVA are executed first.
AddressOfEntryPoint := ;
//Specify the entry address to the RVA (relative virtual address) of the newly added section table
:=
;
//win32 subsystem version.
:= 7;
:= 0;
AddressOfEntryPoint := AddressOfEntryPoint +
;
asm // Let me explain here that this is embedded assembly code, registers—the thing that the CPU temporarily stores data, faster than memory to improve efficiency.
PUSHAD
LEA eax, OEPCODE //Talk the address of OEPCODE to the register
ADD eax, JMPOFF //Add JMPOFF value to register
MOV edx, AddressOfEntryPoint //Transfer instruction, equivalent to a value statement, the left side is given to the right side
MOV DWORD ptr [eax], edx //Similar to
POPAD
end;
//Change the size of the entire PE image body in memory
:=
+ ;
//Write PEHEADER information
(PEHEADER, sizeof(PEHEADER));
//Move the pointer to the end of the file
(, soFromBeginning);
//Write flower instruction data
(OEPCODE, );
finally
;
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
if then
:=;
end;
procedure ;
var
DOSHEADER: IMAGE_DOS_HEADER;
PEHEADER: IMAGE_NT_HEADERS;
fs: TFileStream;
begin
fs := (, fmOpenReadWrite +
fmShareDenyWrite);
try
(0, soFromBeginning);
(DOSHEADER, sizeof(DOSHEADER));
(DOSHEADER._lfanew, soFromBeginning);
(PEHEADER, sizeOf(PEHEADER));
FImageBase := ;
finally
;
end;
end;
procedure TForm1.Button2Click(Sender: TObject);
var
FName,SecName:string;
SecSize:DWord;
begin
if trim() = '' then
begin
Messagebox(Handle, 'Please select the program you want to disguise!', 'Tip', MB_OK + MB_ICONSTOP);
Exit;
end;
FName :=trim();
SecName :=trim();
if SecName='' then SecName:='.hnxyy';
SecSize :=512;
if trim()<>'' then
begin
SecSize :=strtoint(trim());
if SecSize<512 then SecSize :=512;
end;
if then
CopyFile(PChar(FName),PChar(Fname+'.bak'),False);
SetOepCode;
AddSection(FName,SecName,SecSize);
Messagebox(Handle, 'Disguise Successfully!', 'Tip', MB_OK + MB_ICONINFORMATION);
end;
procedure ;
begin
OEPCODE :=OEPCODEARRAY[];
JMPOFF :=JMPOFFARRAY[];
end;
procedure TForm1.Label4Click(Sender: TObject);
begin
ShellExecute(Handle, 'open','', '', '', SW_SHOWNORMAL);
end;
procedure TForm1.Edit3KeyPress(Sender: TObject; var Key: Char);
begin
if not (key in ['0'..'9',#8,#13]) then
begin
key :=#0;
end;
end;
end.