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; //节表 MySectionHeader: IMAGE_SECTION_HEADER; //自定义节表 fs: TFileStream; AddressOfEntryPoint: DWORD; //入口点 i:integer; begin fs := TFileStream.Create(FName, fmOpenReadWrite + fmShareDenyWrite); try {Tstream中定义的虚方法有四个: 1、Read:此方法实现将数据从流中读出。函数原形为: Function Read(var Buffer;Count:Longint):Longint;virtual;abstract; 参数Buffer为数据读出时放置的缓冲区,Count为需要读出的数据的字节数,该方法返回值为实际读出的字节数,它可以小于或等于Count中指定的值。 2、Write:此方法实现将数据写入流中。函数原形为: Function Write(var Buffer;Count:Longint):Longint;virtual;abstract; 参数Buffer为将要写入流中的数据的缓冲区,Count为数据的长度字节数,该方法返回值为实际写入流中的字节数。 3、Seek:此方法实现流中读取指针的移动。函数原形为: Function Seek(Offset:Longint;Origint:Word):Longint;virtual;abstract; 参数Offset为偏移字节数,参数Origint指出Offset的实际意义,其可能的取值如下: soFromBeginning:Offset为移动后指针距离数据开始的位置。此时Offset必须大于或者等于零。 soFromCurrent:Offset为移动后指针与当前指针的相对位置。 soFromEnd:Offset为移动后指针距离数据结束的位置。此时Offset必须小于或者等于零。该方法返回值为移动后指针的位置。 4、Setsize:此方法实现改变数据的大小。函数原形为: Function Setsize(NewSize:Longint);virtual; } //将指针偏移量放到文件头部 fs.Seek(0, soFromBeginning); //读取DOS头信息 fs.Read(DOSHEADER, sizeof(DOSHEADER)); //DOS MZ header 又命名为 IMAGE_DOS_HEADER.。其中只有两个域比较重要: //e_magic 包含字符串"MZ",e_lfanew 包含PE header在文件中的偏移量。 //将指针移到PE header在文件中的偏移量 fs.Seek(DOSHEADER._lfanew, soFromBeginning); //读取PE header头信息 fs.Read(PEHEADER, sizeOf(PEHEADER)); //PEHEADER.FileHeader.NumberOfSections:文件的节数目。如果我们要在文件中增加或删除一个节,就需要修改这个值。 //将指针移到节表在当前位置的相对偏移量 fs.Seek(sizeOf(SectionHeader) * (PEHEADER.FileHeader.NumberOfSections - 1), soFromCurrent); //读取节表的信息 fs.Read(SectionHeader, sizeof(IMAGE_SECTION_HEADER)); //节名长不超过8字节。记住节名仅仅是个标记而已,我们选择任何名字甚至空着也行 { MySectionHeader.Name[0] := ord(''''F''''); MySectionHeader.Name[1] := ord(''''i''''); MySectionHeader.Name[2] := ord(''''7''''); MySectionHeader.Name[3] := ord(''''k''''); MySectionHeader.Name[4] := ord(''''e''''); MySectionHeader.Name[5] := 0; MySectionHeader.Name[6] := 0; MySectionHeader.Name[7] := 0; } for i:=0 to 7 do begin MySectionHeader.Name[i] :=0; if i<length(MySection) then MySectionHeader.Name[i] :=Ord(MySection[i+1]); end; //VirtualAddress 本节的RVA(相对虚拟地址)。PE装载器将节映射至内存时会读取本值,因此如果域值是1000h, //而PE文件装在地址400000h处,那么本节就被载到401000h。 //SizeOfImage 内存中整个PE映像体的尺寸。它是所有头和节经过节对齐处理后的大小。 MySectionHeader.VirtualAddress := PEHEADER.OptionalHeader.SizeOfImage; //节的大小 $200十六进制 = 512字节 最好大于 512 不然可能会出错 //MySectionHeader.Misc.VirtualSize := $200; MySectionHeader.Misc.VirtualSize := SecSize; //StrToInt(IntToHex(SecSize,sizeof(SecSize))); //SizeOfRawData 经过文件对齐处理后节尺寸,PE装载器提取本域值了解需映射入内存的节字节数。 //(译者注: 假设一个文件的文件对齐尺寸是0x200,如果前面的 VirtualSize域指示本节长度是0x388字节, //则本域值为0x400,表示本节是0x400字节长)。 //FileAlignment 文件中节对齐的粒度。例如,如果该值是(200h),,那么每节的起始地址必须是512的倍数。 //若第一节从文件偏移量200h开始且大小是10个字节,则下一节必定位于偏移量400h: //即使偏移量512和1024之间还有很多空间没被使用/定义。 MySectionHeader.SizeOfRawData := (MySectionHeader.VirtualAddress div PEHEADER.OptionalHeader.FileAlignment + 1) * PEHEADER.OptionalHeader.FileAlignment - PEHEADER.OptionalHeader.SizeOfImage; //这是节基于文件的偏移量,PE装载器通过本域值找到节数据在文件中的位置。 MySectionHeader.PointerToRawData := SectionHeader.SizeOfRawData + SectionHeader.PointerToRawData; //包含标记以指示节属性,比如节是否含有可执行代码、初始化数据、未初始数据,是否可写、可读等。 MySectionHeader.Characteristics := $E0000020; {PE装载器的工作: 1.读取 IMAGE_FILE_HEADER 的 NumberOfSections域,知道文件的节数目。 2.SizeOfHeaders 域值作为节表的文件偏移量,并以此定位节表。 3.遍历整个结构数组检查各成员值。 4.对于每个结构,我们读取PointerToRawData域值并定位到该文件偏移量。然后再读取SizeOfRawData域值来决定 映射内存的字节数。将VirtualAddress域值加上ImageBase域值等于节起始的虚拟地址。然后就准备把节映射进内存, 并根据Characteristics域值设置属性。 5.遍历整个数组,直至所有节都已处理完毕。 注意我们并没有使用节名: 这其实并不重要。} //节表数量加一 Inc(PEHEADER.FileHeader.NumberOfSections); //写入新加入的节表 fs.Write(MySectionHeader, sizeOf(MySectionHeader)); //将指针移到PE header在文件中的偏移量 fs.Seek(DOSHEADER._lfanew, soFromBeginning); //PE装载器准备运行的PE文件的第一个指令的RVA。若您要改变整个执行的流程, //可以将该值指定到新的RVA,这样新RVA处的指令首先被执行。 AddressOfEntryPoint := PEHEADER.OptionalHeader.AddressOfEntryPoint; //将入口地址指定到新加节表的RVA(相对虚拟地址) PEHEADER.OptionalHeader.AddressOfEntryPoint := MySectionHeader.VirtualAddress; //win32子系统版本。 PEHEADER.OptionalHeader.MajorLinkerVersion := 7; PEHEADER.OptionalHeader.MinorLinkerVersion := 0; AddressOfEntryPoint := AddressOfEntryPoint + PEHEADER.OptionalHeader.ImageBase; asm //这里说明一下,这是嵌入的汇编代码,寄存器—CPU暂时储存数据的东西,比内存更快,以提高效率 PUSHAD LEA eax, OEPCODE //将OEPCODE的地址交给寄存器 ADD eax, JMPOFF //添加JMPOFF值给寄存器 MOV edx, AddressOfEntryPoint //转移指令,相当于付值语句,左边给右边 MOV DWORD ptr [eax], edx //同上 POPAD end; //更改内存中整个PE映像体的尺寸 PEHEADER.OptionalHeader.SizeOfImage := PEHEADER.OptionalHeader.SizeOfImage + MySectionHeader.Misc.VirtualSize; //写入PEHEADER信息 fs.Write(PEHEADER, sizeof(PEHEADER)); //移动指针到文件尾部 fs.Seek(fs.Size, soFromBeginning); //写入花指令数据 fs.Write(OEPCODE, MySectionHeader.Misc.VirtualSize); finally fs.Free; end; end; procedure TForm1.Button1Click(Sender: TObject); begin if OpenDialog1.Execute then edit1.Text :=OpenDialog1.FileName; end; procedure TForm1.obtain; var DOSHEADER: IMAGE_DOS_HEADER; PEHEADER: IMAGE_NT_HEADERS; fs: TFileStream; begin fs := TFileStream.Create(Edit1.Text, fmOpenReadWrite + fmShareDenyWrite); try fs.Seek(0, soFromBeginning); fs.Read(DOSHEADER, sizeof(DOSHEADER)); fs.Seek(DOSHEADER._lfanew, soFromBeginning); fs.Read(PEHEADER, sizeOf(PEHEADER)); FImageBase := PEHEADER.OptionalHeader.ImageBase; finally fs.Free; end; end; procedure TForm1.Button2Click(Sender: TObject); var FName,SecName:string; SecSize:DWord; begin if trim(Edit1.Text) = '''''''' then begin Messagebox(Handle, ''''请选择你要伪装的程序!'''', ''''提示'''', MB_OK + MB_ICONSTOP); Exit; end; FName :=trim(Edit1.Text); SecName :=trim(Edit2.Text); if SecName='''''''' then SecName:=''''.hnxy 上一页 [1] [2] [3] [4] 下一页 没有相关教程
|