• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 210
  • Last Modified:

Find and Replace Stream with 0s

Greetings Sir,

I want to search the contents of a stream in a binary file and replace all the bytes present in it with 0s. I tried to implement it by taking the first 10 bytes of the stream and searching them in the file, then if >1 matches are found, confirmed it by SHA1. But it seems to be bugged and slow. Can ya please tell me how to do it?
0
Abhishek Sharma
Asked:
Abhishek Sharma
  • 3
  • 2
  • 2
  • +1
1 Solution
 
mlmccCommented:
Are you trying to create a stream of 0s?

mlmcc
0
 
Abhishek SharmaAuthor Commented:
I'm trying to replace all the data in b/w two offsets with 0s, i.e., if I had data = "ABCDEFGHIJKLM" and I give offset of 4 and size 2, then it should become like this "ABCD00GHIJKLM". Just the binary version of it.
0
 
Geert GOracle dbaCommented:
What code have you got so far ?
0
Cloud Class® Course: Certified Penetration Testing

This CPTE Certified Penetration Testing Engineer course covers everything you need to know about becoming a Certified Penetration Testing Engineer. Career Path: Professional roles include Ethical Hackers, Security Consultants, System Administrators, and Chief Security Officers.

 
Sinisa VukCommented:
I would use memory mapped file and search through it with CompareMem function, replace with CopyMemory.... This is possible because with memory mapped file - you get pointer to "memory" which is great for CompareMem.
0
 
Geert GOracle dbaCommented:
you'll have to open the file for read/write and read all the contents piece by piece and replace the bytes
i wrote something like this once, for in place byte updates in a file

here are some samples:
https://www.experts-exchange.com/questions/26386805/How-do-I-Write-a-String-at-the-very-top-of-a-Text-file.html
https://www.experts-exchange.com/questions/23347230/Need-make-Seek-function-for-text-file.html#a21429333
0
 
Abhishek SharmaAuthor Commented:
I ended up writing one code too, but it's giving StackOverflow on big scan inputs:

program Project2;

{$APPTYPE CONSOLE}
{$R *.res}
{$optimization on}

uses
  WinAPI.Windows,
  System.SysUtils,
  System.Classes,
  System.Math;

type
  TByteArray = Array of Byte;

function StreamToByteArray(Stream: TStream): TByteArray;
begin
  if Assigned(Stream) then
  begin
    Stream.Position := 0;
    SetLength(result, Stream.Size);
    Stream.Read(result[0], Stream.Size);
  end
  else
    SetLength(result, 0);
end;

procedure FindHeader(FileName: string; Sequence: array of Byte;
  var List: TStringList);
var
  Buffer: array of Byte;
  Fs: TBufferedFileStream;
  l, n, sl: Int64;
  ScanStopped: boolean;

begin
  List.Clear;
  sl := length(Sequence);
  if sl = 0 then
    Exit;

  Fs := TBufferedFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite,
    4 * 1024 * 1024);
  try
    SetLength(Buffer, Fs.Size);
    Fs.Read(Buffer[0], Fs.Size);
    for l := 0 to Fs.Size - 1 do
    begin
      if Buffer[l] = Sequence[0] then
      begin
        if sl = 1 then
          List.Add(IntToStr(l))
        else
        begin
          n := 1;
          ScanStopped := false;
          while n < sl do
          begin
            if Buffer[l + n] <> Sequence[n] then
            begin
              ScanStopped := true;
              Break;
            end;
            Inc(n);
          end;
          if not ScanStopped then
            List.Add(IntToStr(l));
        end;
      end;
    end;
  finally
    Finalize(Buffer);
    Fs.Free;
  end;
end;

var
  raw: TMemoryStream;
  null: array [0 .. 0] of Byte = (
    $00
  );
  pos: TStringList;
  I, j: Int64;
  start, stop, elapsed: cardinal;
  infile, scanfile: TBufferedFileStream;

begin
  start := GetTickCount;
  pos := TStringList.Create;
  j := 0;
  try
    scanfile := TBufferedFileStream.Create(paramstr(2), fmOpenReadWrite);
    raw := TMemoryStream.Create;
    if scanfile.Size > 1024 * 1024 then
      raw.CopyFrom(scanfile, 1024 * 1024)
    else
      raw.CopyFrom(scanfile, 0);
    scanfile.Free;
    FindHeader(paramstr(1), StreamToByteArray(raw), pos);
    writeln('Possible offsets found: ' + IntToStr(pos.Count));
    infile := TBufferedFileStream.Create(paramstr(1), fmOpenReadWrite);
    if pos.Count <> 0 then
    begin
      infile.Seek(strtoint(pos[0]), soFromBeginning);
      for I := 0 to raw.Size - 1 do
      begin
        infile.Write(null, 1);
      end;
    end;
  finally
    pos.Free;
    raw.Free;
    infile.Free;
  end;
  stop := GetTickCount;
  elapsed := stop - start;
  writeln('Time Taken: ' + IntToStr(elapsed) + ' ms');

end.

Open in new window

0
 
Geert GOracle dbaCommented:
well yeah, you put the whole stream in memory with this function StreamToByteArray
why ?

read a chunk, analyze it for the items, update the positions on file, read next check,
repeat until Jezus Christ returns or EOF
0
 
Sinisa VukCommented:
Try my piece of code for finding first position (with a replacing):
function MMFReplace(FileName: String; pFindWhat: TByteDynArray; pReplaceWith: TByteDynArray): Boolean;

  function MakeInt64 (H,L: DWord): Int64;
  begin
    Result := H or (L shl 32);
  end;

var
  hFile: THandle;
  hFileMap: THandle;
  hiSize, loSize: DWORD;
  pFileView: Pointer;
  lFileSz, lFind, lReplace: Int64;
  i: Cardinal;
begin
  Result := False;
  if FileName = '' then Exit;

  lFind := Length(pFindWhat);
  lReplace := Length(pReplaceWith);
  //check if parameter are same length
  //if Length(pFindWhat) <> Length(pReplaceWith) then Exit;

  //open the file...
  hFile := CreateFile(
    PChar(FileName), GENERIC_READ or GENERIC_WRITE, FILE_SHARE_READ or FILE_SHARE_WRITE, nil,
    OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);

  if hFile <> INVALID_HANDLE_VALUE then
  begin
    try
      loSize := GetFileSize(hFile, @hiSize);
      lFileSz := MakeInt64(hiSize, loSize);

      //create file mapping....
      hFileMap := CreateFileMapping(hFile, nil, PAGE_READWRITE, hiSize, loSize,  'Find_And_Replace_MMF');

      if hFileMap <> 0 then
      begin
        try
          //create map view....
          pFileView := MapViewOfFile(hFileMap, FILE_MAP_READ or FILE_MAP_WRITE, 0, 0, 0);
          if pFileView <> nil then
          begin
            try
              //try to find ..
              for i := 0 to lFileSz - lFind - 1 do
              begin
                //compare bytes...
                if CompareMem(Pointer(Cardinal(pFileView)+i), @pFindWhat[0], lFind) then
                begin
                  //found it... replace
                  if lReplace>0 then
                    MoveMemory(Pointer(Cardinal(pFileView)+i), @pReplaceWith[0], lReplace);
                  Result := True;
                  Break;
                end;
              end;
            finally
              UnmapViewOfFile(pFileView);
            end;
          end;
        finally
          CloseHandle(hFileMap);
        end;
      end;
    finally
      CloseHandle(hFile);
    end;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  sFind, sReplace: TByteDynArray;
begin
  SetLength(sFind, 4);
  sFind[0] := Ord('5');
  sFind[1] := Ord('0');
  sFind[2] := Ord('0');
  sFind[3] := Ord('2');

  SetLength(sReplace, 4);
  sReplace[0] := Ord('5');
  sReplace[1] := Ord('0');
  sReplace[2] := Ord('0');
  sReplace[3] := Ord('3');

  if MMFReplace('C:\Temp\myfile.txt', sFind, sReplace) then
    ShowMessage('Found!');
end;

Open in new window

0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Get your problem seen by more experts

Be seen. Boost your question’s priority for more expert views and faster solutions

  • 3
  • 2
  • 2
  • +1
Tackle projects and never again get stuck behind a technical roadblock.
Join Now