怎样以流的形式往自身文件后面写东西,删东西。

解决方案 »

  1.   

    : Mercedes() (2001-8-30 8:41:05)  得0分 
    前几天才刚刚在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.
      

  2.   


    ================
    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 :-)
     
    --------------------------------------------------------------------------------
    ***************************************
    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;
      

  3.   

    写东西其实不难,如果你会用tstream属性的话,那么,先把文件读到流中,然后copy到内存流Tmemorystream中,然后把流的指针移到到最后,接着把要写入的内容也读到内存流中,然后计算其大小,最后把两个内存流合并然后保存为文件就可以了,删除东西其实和这个原理是一样的,
      

  4.   

    看看《Delphi下深入Windows核心编程》原书光盘中文件加壳的例子应该对你有帮助,在www.2ccc.com或www.playicq.com有下载
      

  5.   

    dacong(大聪) 
    拷到软盘上可以使用是因为
    操作系统在运行软盘上的俄exe文件时,
    是先将整个文件拷入ram中在运行的
    也就是说软盘拿掉也不会影响其运行
    所以读写软盘文件是可以的但读写硬盘文件就不可以,
    是因为没有将文件全部加载到内存中,
    硬盘文件受到保护
    我想知道,
    操作系统在运行exe文件是向内存中加载了什么?
    能不能,把整个文件全加载到内存中?还望指教!!
      

  6.   

    function TForm1.Cjt_AddtoFile(SourceFile, TargetFile: string): Boolean;
    var
      Target,Source:TFileStream;
      MyFileSize:integer;
    begin
      try
        Source:=TFileStream.Create(SourceFile,fmOpenRead or fmShareExclusive);
        Target:=TFileStream.Create(TargetFile,fmOpenWrite or fmShareExclusive);
        try
          Target.Seek(0,soFromEnd);//往尾部添加资源
          Target.CopyFrom(Source,0);
          MyFileSize:=Source.Size+Sizeof(MyFileSize);//计算资源大小,并写入辅程尾部
          Target.WriteBuffer(MyFileSize,sizeof(MyFileSize));
        finally
        Target.Free;
        Source.Free;
        end;
      except
        Result:=False;
        Exit;
      end;
      Result:=True;
    end;
    function TForm1.Cjt_BmpLoad(ImgBmp: TImage; SourceFile: String): Boolean;
    var
      Source:TFileStream;
      MyFileSize:integer;
    begin
      Source:=TFileStream.Create(SourceFile,fmOpenRead or fmShareDenyNone);
      try
        try
          Source.Seek(-sizeof(MyFileSize),soFromEnd);
          Source.ReadBuffer(MyFileSize,sizeof(MyFileSize));//读出资源
          Source.Seek(-MyFileSize,soFromEnd);//定位到资源开始位置
          ImgBmp.Picture.Bitmap.LoadFromStream(Source);
          finally
            Source.Free;
          end;
      except
      Result:=False;
      Exit;
      end;
      Result:=True;
    end;function TForm1.Cjt_JpgLoad(JpgImg: Timage; SourceFile: String): Boolean;
    var
      Source:TFileStream;
      MyFileSize:integer;
      Myjpg: TJpegImage;
    begin
      try
        Myjpg:= TJpegImage.Create;
        Source:=TFileStream.Create(SourceFile,fmOpenRead or fmShareDenyNone);
        try
          Source.Seek(-sizeof(MyFileSize),soFromEnd);
          Source.ReadBuffer(MyFileSize,sizeof(MyFileSize));
          Source.Seek(-MyFileSize,soFromEnd);
          Myjpg.LoadFromStream(Source);
          JpgImg.Picture.Bitmap.Assign(Myjpg);
        finally
          Source.Free;
          Myjpg.free;
        end;
      except
        Result:=false;
        Exit;
      end;
      Result:=true;
    end;
    function TForm1.ExtractRes(ResType, ResName, ResNewName: String): boolean;
    var
      Res : TResourceStream;
    begin
      try
        Res := TResourceStream.Create(Hinstance, Resname, Pchar(ResType));
        try
          Res.SavetoFile(ResNewName);
          Result:=true;
        finally
          Res.Free;
        end;
      except
        Result:=false;
      end;
    end;procedure TForm1.FormCreate(Sender: TObject);
    begin
      OpenPictureDialog1.DefaultExt := GraphicExtension(TBitmap);
      OpenPictureDialog1.Filter := GraphicFilter(TBitmap);
    end;procedure TForm1.Button1Click(Sender: TObject);
    begin
       if OpenPictureDialog1.Execute then
          Edit1.Text:=OpenPictureDialog1.FileName;
    end;procedure TForm1.Button2Click(Sender: TObject);
    var
      HeadTemp:String;
    begin
      if Not FileExists(Edit1.Text) then
      begin
        Application.MessageBox('BMP图片文件不存在,请重新选择!','信息',MB_ICONINFORMATION+MB_OK);
        Exit;
      end;
      HeadTemp:=ChangeFileExt(Edit1.Text,'.exe');
      if ExtractRes('exefile','head',HeadTemp) then
      if Cjt_AddtoFile(Edit1.Text,HeadTemp) then
        Application.MessageBox('EXE文件生成成功!','信息',MB_ICONINFORMATION+MB_OK)
      else
      begin
        if FileExists(HeadTemp) then DeleteFile(HeadTemp);
          Application.MessageBox('EXE文件生成失败!','信息',MB_ICONINFORMATION+MB_OK)
      end;
    end;
      

  7.   

    其实你问题和一个exe如何删除自己有共通之处,读显然是没有问题的,但说起写,基本没有很直接的解决方法了
      

  8.   

    一个exe删除自己是在结束该程序进程以后
    用批处理文件删除的。
      
    winapi 中哪个函数是把程序本身,全部加到内存中?
    有没有人知道 CIH的运行原理?
    我想知道cih 是感染正在运行的exe文件还是感染没有运行的exe文件?
      

  9.   

    贴一个别人的例子好了unit Unit1;interfaceuses
      Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
      ComCtrls, StdCtrls;type
      TForm1 = class(TForm)
        Button1: TButton;
        StatusBar1: TStatusBar;
        procedure FormCreate(Sender: TObject);
        procedure Button1Click(Sender: TObject);
        procedure FormClose(Sender: TObject; var Action: TCloseAction);
      private
        { Private declarations }
      public
        { Public declarations }
      end;var
      Form1: TForm1;
      TempName: string;implementation{$R *.DFM}procedure TForm1.FormCreate(Sender: TObject);
    var
      Sr: TSearchRec;
      size : Longint;
    begin
      FindFirst(ParamStr(0),$27,Sr); //($27)为文件属性
      size:=Sr.Size;
      FindClose(Sr);
      StatusBar1.SimpleText:='本程序大小为 '+IntToStr(size)+' 字节';
    end;procedure TForm1.Button1Click(Sender: TObject);
    var
      Dir: PChar;
      Ch: Array[0..3] of Char;
      Stream1,Stream2: TMemoryStream;
    begin
      //分配空间
      GetMem(Dir,254);
      //取得临时路径
      GetTempPath(254, Dir);
      //设定文件名
      TempName:=StrPas(Dir)+'o.o.0.o.o.exe';
      //创建备份文件
      CopyFile(PChar(ParamStr(0)),PChar(TempName),False);
      //内存文件的创建
      Stream1:=TMemoryStream.Create;
      Stream2:=TMemoryStream.Create;
      //将临时文件导入内存
      Stream1.LoadFromFile(TempName);
      //在尾部加入4个随机字节
      Randomize;
      Ch[0]:=Chr(Random(256));
      Ch[1]:=Chr(Random(256));
      Ch[2]:=Chr(Random(256));
      Ch[3]:=Chr(Random(256));
      Stream1.Seek(0,soFromEnd);
      Stream1.Write(Ch,4);
      //修改偏移48的一个字节,记录程序运行次数  Stream1.Seek(0,soFromBeginning);
    {  Stream2.CopyFrom(Stream1,48);
      Stream1.Seek(48,soFromBeginning);
      Stream1.Read(Ch,1);
      Ch[0]:=Chr(1+Ord(Ch[0]));
      Stream2.Write(Ch,1);
      Stream1.Seek(49,soFromBeginning);
      Stream2.CopyFrom(Stream1,Stream1.Size-49);
      Stream2.SaveToFile(TempName);
    }
      Stream1.Free;
      Stream2.Free;
      FreeMem(Dir);
    //  repeat Close Until FileExists(TempName);
    end;procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
    begin
    //  WinExec(PChar(TempName+'  '+ParamStr(0)), SW_SHOWNORMAL);
    end;end.
      

  10.   

    http://free.efile.com.cn/gaodu2003/UFO/changeself.rar如要完整程序,可到上面地址下载