Page 1 of 3 123 LastLast
Results 1 to 10 of 21
  1. #1
    RiiStar
    RiiStar is offline
    New member
    Join Date
    2011 Jun
    Posts
    17
    Thanks Thanks Given 
    0
    Thanks Thanks Received 
    1
    Thanked in
    1 Post
    Rep Power
    0

    Memory Search Function - Help please? ^^

    A friend and i have being using/making/coding memory loaders/patchers in C++

    For an interesting challenge we decided to try make a new lib using Delphi.
    Now we could do the basic memory editing to fixed pointer addresses fairly easily but i did find Dwar's tutorials very very helpful in making sure what we did was correct using Delphi.

    So now on to my question / issue - as part of our patcher lib we wanted a memory search function, something to match byte patterns with. In the end I ported the Boyer-Moore-Horspool method function that my friend wrote up in C++ over to Delphi.

    Now it compiles and "seems" to work, but we know for a fact that it returns the wrong pointer address to the bytes that we want to match and edit. So somewhere in there it's not calculating the correct pointer.

    I was hoping Dwar could see whats wrong with our function or suggest a better way of doing this in Delphi

    Im sure this would benefit others as well if you can help us out!

    Here's the ported function

    PHP Code:
    Function SearchMemory(SearchDLLhModulewildcardBytesearchCode: Array of BytesizeInteger) : Pointer;
    Const
      
    UCHAR_MAX 255;
    Var
      
    scan,lastByte,defaultSkip,pIDsearchEnd Cardinal;
      
    skipLength : ARRAY of Integer;
      
    dllInfo TModuleInfo;
      
    pointer;
      
    pbCurrentPByte;
      
    bByte;
    begin

      
    //WriteLog('Hai loop');

      //The first loop builds the skip length for characters that aren't in the searched "string"
      
    lastByte := size 1;
      while 
    searchCode[lastByte] = wildcard do
            
    Dec(lastByte);

        
    defaultSkip := lastByte;

      
    //WriteLog('Second loop');

      //The second one builds the skip length for the characters in the string
      
    scan := 0;
      for 
    scan:= 0 to  lastByte do
      
    begin
            
    if searchCode[scan] = wildcard then defaultSkip := lastByte scan;
      
    end;

      if 
    defaultSkip 1 then defaultSkip := defaultSkip 1;

      
    //WriteLog('Skiplen loop');

      //Is just setting the default skip length
      
    SetLength(skipLengthUCHAR_MAX);
      for 
    scan:=0 to UCHAR_MAX do
        
    skipLength[scan] := defaultSkip;

      
    //WriteLog('Third loop');

      //Third loop searches for the string, skipping bytes based on the skip length
      
    for scan:= 0 to lastByte do
      
    begin
            
    if searchCode[scan] <> wildcard then
        begin
                skipLength
    [searchCode[scan]] := lastByte scan;
        
    end;
      
    end;

      
    pID := GetCurrentProcessID;
        
    GetModuleInformation(pIDSearchDLL, @dllInfosizeof(dllInfo));

        
    := dllInfo.lpBaseOfDll;
        
    searchEnd := Cardinal(dllInfo.lpBaseOfDll) + dllInfo.SizeOfImage;
        
    searchEnd := searchEnd - (lastByte 1);

      
    //WriteLog(Format('Checking addr: %p,  SearchEnd: %08X', [p, searchEnd]));

        
    while Cardinal(p) <= searchEnd do
      
    begin
        
    //WriteLog(Format('Checking addr: %p', [p]));
        
    pbCurrent := PByte(Cardinal(p) + lastByte);
            while ((
    searchCode[scan] = wildcard) or (pbCurrent^ = searchCode[scan])) do
        
    begin
                
    if Cardinal(pbCurrent) = Cardinal(pthen
          begin
            result 
    := p;
            Exit;
          
    end
          
    else Dec(pbCurrent);
            
    end;
        
    Move(bPointer(Cardinal(p) + lastByte)^, 1); // Wtf how would you do this. Hmm
            
    := Pointer(Cardinal(p) + skipLength[b]);
      
    end;

      
    result:= 0;
    end
    Link to post to a working version of function: Here
    Last edited by RiiStar; 2011-10-17 at 08:41 AM.

  2. #2
    Dwar
    Dwar is offline
    Veteran Dwar's Avatar
    Join Date
    2010 Mar
    Posts
    2,222
    Thanks Thanks Given 
    211
    Thanks Thanks Received 
    2,230
    Thanked in
    292 Posts
    Rep Power
    10
    Hm, if you try to find something in a memory of selected process, you can't just set the range of memory and read it byte-by-byte for comparison. Memory in Win is organized more complex than my example above
    Note: you can again check Jeffrey Richter's book about internal structure of Win OS. He brilliantly described memory structure.
    One of the good example how to scan memory is here: https://progamercity.net/c-code/904-...console-c.html
    What about your code.. You should map memory, count memory blocks and then loop through all blocks for your value

    I will post soon some examples, how to perform memory search in delphi
    Please, post your questions on forum, not by PM or mail

    I spend my time, so please pay a little bit of your time to keep world in equilibrium

  3. #3
    RiiStar
    RiiStar is offline
    New member
    Join Date
    2011 Jun
    Posts
    17
    Thanks Thanks Given 
    0
    Thanks Thanks Received 
    1
    Thanked in
    1 Post
    Rep Power
    0
    The function or parent of that function works perfectly fine in C++ but i guess my port of it wasn't good.

    I was looking at memory mapping, i have not really used it before. Examples would be greatly appreciated!

  4. #4
    Dwar
    Dwar is offline
    Veteran Dwar's Avatar
    Join Date
    2010 Mar
    Posts
    2,222
    Thanks Thanks Given 
    211
    Thanks Thanks Received 
    2,230
    Thanked in
    292 Posts
    Rep Power
    10
    Quote Originally Posted by RiiStar View Post
    works perfectly fine in C++
    We should check your delphi function with debugger, 'cuz without deep analyzing I can't say where is your mistake.

    About examples... hm, best variant is a code from CheatEngine by DarkByte (all credits goes to him). My code is close to DarkByte's code, + Boyer-Moore alg
    Code:
    unit MainUnit;
    
    interface
    
    uses
      Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
      ImgList, Menus, ComCtrls, ToolWin, ExtCtrls, TlHelp32, StdCtrls, AppEvnts;
    
    
      // This type can hold an offset and the size of the data to be read. It is
      // used a lot in the search and seive functions.
      TMappedAddress = Record
        dwAddress : Cardinal;
        dwSize : Cardinal;
      End;
    
      // Used to allocate new cheats dynamically
      PCheat = ^TCheat;
    
      // Holds info about each cheat
      TCheat = Record
        Address, Value : Cardinal;
        Size : Byte;
        Freeze : Boolean;
        Description : String[50];
      end;
    
      // This just tells us what the current data type to search for is. It is used
      // to autoselect a Data Type in the seive and find dialogs.
      SearchMode = (smByte, smWord, smDWORD);
    
      // The range type
      SearchRange = (srWin16, srWin32);
    
    var
      Process : TProcessEntry32; // This holds info about the open process
      Mapped : Array of TMappedAddress; // This holds all the info about the R/W memory blocks
      iSC : Integer; // The number of R/W blocks in Mapped
      List : TList; // The list of results from the search
      Mode : SearchMode; // The current search mode (smByte, smWord, smDword)
      FoundIn : Array of Boolean; // This keeps track of where results were found (speeds things up)
      Cheats : TList; // This holds a list of pointers to the cheats
      bIsDirty : Boolean; // This keeps track of whether the cheat list has been changed (needs saving)
      MaxResults : Integer; // Specifies the maximum number of results to display
      Range : SearchRange; // The range of memory to search
    
    implementation
    
    uses SelectProcessUnit, SearchingUnit, AboutUnit, FindUnit, IniFiles, AddCheatUnit,
      OptionsUnit, TCUnit;
    
    {$R *.DFM}
    
    // This converts a hex string back to an integer
    Function HexToInt(HexString : String) : integer;
    begin
      // Add a "$" to the hex string. Delphi uses "$" incstead of C++'s
      // "0x" to denote hex values
      HexString := '$' + HexString;
    
      // Use Delphi's built-in StrToInt function to convert the hex string back to
      // an integer.
      Result := StrToInt(HexString);
    end;
    
    Procedure TMainForm.FindValue(Data : Integer; Size : Byte; BufferSize : Integer);
    var
      hProcess : THandle;
      iCurBlock : Integer;
      iCurByte : Integer;
      iBytesRead : Cardinal;
      Bytes : Array of Byte;
      dwStart, dwStop : DWORD;
      iResultCount : Cardinal;
      d, e : Cardinal;
      i : integer;
      xByte : Byte;
      xWord, xWord2 : Word;
      xDword, xDword2 : DWORD;
      Form : TSearchingForm;
      Item : TListItem;
      SaveCursor : TCursor;
    begin
      // Assign the value to the correct variable
      Case Size Of
      1:
        xByte := Data;
      2:
        xWord := Data;
      4:
        xDword := Data;
      Else
      begin
        ShowMessage('Bad data size!');
        Exit;
      end;
      End;
    
      Timer.Enabled := False;
    
      SaveCursor := Screen.Cursor;
      Screen.Cursor := crHourglass;
    
      // Clear and free the current list of results
      List.Clear;
      List.Free;
    
      // Clear the listview with the results
      Results.Items.Clear;
    
      // Create the list again
      List := TList.Create;
    
      // Create the status form
      Form := TSearchingForm.Create(Self);
      // Show the status form
      Form.Show;
      // Map the R/W memory locations and optimize them
      MapMemory(BufferSize, Size);
      // Set the max to the number of blocks to search
      Form.Progress.Max := iSC;
      // Set the size of the buffer to the buffer size
      SetLength(Bytes, BufferSize + (Size - 1));
    
      SetLength(FoundIn, iSC);
    
      // Open the process
      hProcess := OpenProcess(PROCESS_VM_READ, False, Process.th32ProcessID);
    
      //Get the start time
      dwStart := GetTickCount;
    
      iResultCount := 0;
    
      MainForm.Enabled := False;
    
      Case Size of
      1:
      begin
        // Loop through all the blocks
        For iCurBlock := 0 to iSC-1 do
        begin
          // Read a block into memory
          ReadProcessMemory(hProcess, Pointer(Mapped[iCurBlock].dwAddress), @Bytes[0], Mapped[iCurBlock].dwSize, iBytesRead);
    
          For iCurByte := 0 to iBytesRead-1 do
          begin
            // Check for a match
            If Bytes[iCurByte] = xByte then
            begin
              List.Add(Pointer(Mapped[iCurBlock].dwAddress + iCurByte));
              FoundIn[iCurBlock] := True;
            end;
          end;
    
          // Only update the screen every 100 blocks
          If iCurBlock mod 100 = 0 then
          begin
            Form.Status.Caption := 'Searching block ' + IntToStr(iCurBlock+1) + ' of ' + IntToStr(iSC);
            Form.Progress.Position := Form.Progress.Position + 100;
            Status.Panels[0].Text := IntToStr(List.Count) + ' Results';
    
            // Process the applications message que so the user can SEE the updated staus
            Application.ProcessMessages;
          end;
        end;
      end;
    
      2:
      begin
        // Loop through all the blocks
        For iCurBlock := 0 to iSC-1 do
        begin
          // Read a block into memory
          ReadProcessMemory(hProcess, Pointer(Mapped[iCurBlock].dwAddress), @Bytes[0], Mapped[iCurBlock].dwSize, iBytesRead);
    
          For iCurByte := 0 to iBytesRead-(Size-1) do
          begin
            // Check for a match
            CopyMemory(@xWord2, @Bytes[iCurByte], 2);
    
            If xWord2 = xWord then
            begin
              List.Add(Pointer(Mapped[iCurBlock].dwAddress + iCurByte));
              FoundIn[iCurBlock] := True;
            end;
          end;
    
          // Only update the screen every 100 blocks
          If iCurBlock mod 100 = 0 then
          begin
            Form.Status.Caption := 'Searching block ' + IntToStr(iCurBlock+1) + ' of ' + IntToStr(iSC);
            Form.Progress.Position := Form.Progress.Position + 100;
            Status.Panels[0].Text := IntToStr(List.Count) + ' Results';
    
            // Process the applications message que so the user can SEE the updated staus
            Application.ProcessMessages;
          end;
        end;
      end;
      4:
      begin
        // Loop through all the blocks
        For iCurBlock := 0 to iSC-1 do
        begin
          // Read a block into memory
          ReadProcessMemory(hProcess, Pointer(Mapped[iCurBlock].dwAddress), @Bytes[0], Mapped[iCurBlock].dwSize, iBytesRead);
    
          For iCurByte := 0 to iBytesRead-(Size-1) do
          begin
            // Check for a match
            CopyMemory(@xDword2, @Bytes[iCurByte], 4);
    
            // Compare the values
            If xDword2 = xDword then
            begin
                List.Add(Pointer(Mapped[iCurBlock].dwAddress + iCurByte));
                FoundIn[iCurBlock] := True;
            end;
          end;
    
          // Only update the screen every 100 blocks
          If iCurBlock mod 100 = 0 then
          begin
            Form.Status.Caption := 'Searching block ' + IntToStr(iCurBlock+1) + ' of ' + IntToStr(iSC);
            Form.Progress.Position := Form.Progress.Position + 100;
            Status.Panels[0].Text := IntToStr(List.Count) + ' Results';
    
            // Process the applications message que so the user can SEE the updated staus
            Application.ProcessMessages;
          end;
        end;
      end;
      end;
    
      // Get the stop time
      dwStop := GetTickCount;
    
      Form.Status.Caption := 'Searching block ' + IntToStr(iCurBlock+1) + ' of ' + IntToStr(iSC);
      Form.Progress.Position := Form.Progress.Max;
    
      // Process the applications message que so the user can SEE the updated staus
      Application.ProcessMessages;
    
      // Close the object handle
      CloseHandle(hProcess);
    
      // Free the memory taken up by our temp buffer
      Finalize(Bytes);
      FreeMem(Bytes);
    
      // Say how many results we got
      Status.Panels[0].Text := IntToStr(List.Count) + ' Results';
    
      MainForm.Enabled := True;
    
      // Free the status form
      Form.Free;
    
      // Only show the results if under 50 were found
      If (List.Count <= MaxResults) and (List.Count > 0) then
      begin
        For i := 0 to List.Count-1 do
        begin
          Item := Results.Items.Add;
    
          Item.Caption := IntToHex(Integer(List.Items[i]), 8);
    
          Item.SubItems.Add(IntToStr(Data));
    
          
          SieveResultsMenu.Enabled := True;
          SeiveResultsButton.Enabled := True;
        end;
      end
      else
      if List.Count > MaxResults then
      begin
        MessageBox(Handle, 'Too many results were found! They won''t be shown. Try using the Sieve Search to lower the range.', 'Search Results', MB_ICONINFORMATION);
    
        SieveResultsMenu.Enabled := True;
        SeiveResultsButton.Enabled := True;
      end
      else
      if List.Count = 0 then
      begin
        MessageBox(Handle, 'No results were found!', 'Search Results', MB_ICONERROR);
    
        SieveResultsMenu.Enabled := False;
        SeiveResultsButton.Enabled := False;
      end;
    
      Timer.Enabled := True;
    
      Screen.Cursor := SaveCursor;
    end;
    
    Procedure TMainForm.MapMemory(BufferSize : Integer; DataSize : Integer);
    var
      hProcess : THandle;
      MBI : MEMORY_BASIC_INFORMATION;
      dwAddress : DWORD;
      iR : Integer;
      iBlock : Integer;
      cTotalSize : integer;
      iSaved : Cardinal;
      MaxAddy : Cardinal;
    begin
      Finalize(Mapped);
      FreeMem(Mapped);
    
      cTotalSize := 0;
      iSaved := 0;
    
      iSC := 0;
    
      SetLength(Mapped, 0);
    
      if Range = srWin32 then
      begin
        dwAddress := $400000;
        MaxAddy := $80000000;
      end
      else
      begin
        dwAddress := $80000000;
        MaxAddy := $FFFFFFF;
      end;
    
      hProcess := OpenProcess(PROCESS_QUERY_INFORMATION, False, Process.th32ProcessID);
    
      While (VirtualQueryEx(hProcess, Pointer(dwAddress), MBI, SizeOf(MEMORY_BASIC_INFORMATION)) > 0) and (Integer(MBI.BaseAddress) + MBI.RegionSize < MaxAddy) do
      begin
        If (MBI.Protect = PAGE_READWRITE) and (MBI.Type_9 = MEM_PRIVATE) and ((MBI.State = MEM_COMMIT) or (MBI.State = MEM_RESERVE)) Then
        begin
          iR := MBI.RegionSize;
          iBlock := 0;
    
          Repeat
            If iR <= BufferSize then
            begin
              If iBlock > 0 then
                MBI.BaseAddress := Pointer(Integer(MBI.BaseAddress) - (DataSize - 1));
    
              inc(iSC);
              SetLength(Mapped, iSC);
    
              Mapped[iSC-1].dwAddress := Integer(MBI.BaseAddress) + (MBI.RegionSize - iR);
    
              if iBlock > 0 then
                Mapped[iSC-1].dwSize := iR + (DataSize - 1)
              else
                Mapped[iSC-1].dwSize := iR;
    
              iR := 0;
            end
            else
            begin
              If iBlock > 0 then
                MBI.BaseAddress := Pointer(Integer(MBI.BaseAddress) - (DataSize - 1));
    
              inc(iSC);
              SetLength(Mapped, iSC);
    
              Mapped[iSC-1].dwAddress := Integer(MBI.BaseAddress) + (MBI.RegionSize - iR);
    
              if iBlock > 0 then
                Mapped[iSC-1].dwSize := BufferSize + (DataSize - 1)
              else
                Mapped[iSC-1].dwSize := BufferSize;
    
    
              inc(iBlock);
              iR := iR - BufferSize;
            end;
          Until iR = 0;
    
          inc(cTotalSize, MBI.RegionSize);
        end;
    
        Inc(dwAddress, MBI.RegionSize);
      end;
    
      CloseHandle(hProcess);
    end;
    
    
    end.
    Please, post your questions on forum, not by PM or mail

    I spend my time, so please pay a little bit of your time to keep world in equilibrium

  5. #5
    pkedpker
    pkedpker is offline
    Member-in-training
    Join Date
    2011 Mar
    Posts
    67
    Thanks Thanks Given 
    13
    Thanks Thanks Received 
    41
    Thanked in
    14 Posts
    Rep Power
    0
    Making Subspace/Continuum Hack? your name sounds familiar in the continuum community.

  6. #6
    RiiStar
    RiiStar is offline
    New member
    Join Date
    2011 Jun
    Posts
    17
    Thanks Thanks Given 
    0
    Thanks Thanks Received 
    1
    Thanked in
    1 Post
    Rep Power
    0
    I am RiiStar from Trenchwars, but i quit Continuum and staff over 2 years ago...
    Im actually having fun modding other (RPG) MMO's.

    @Dwar - Seems that function searches for a single value?

    Been awhile but i'll poke around CE's source again for examples.
    Would seeing the orginal function in C++ be helpful? My porting skills aren't really that great so i might have screwed it up...

  7. #7
    Dwar
    Dwar is offline
    Veteran Dwar's Avatar
    Join Date
    2010 Mar
    Posts
    2,222
    Thanks Thanks Given 
    211
    Thanks Thanks Received 
    2,230
    Thanked in
    292 Posts
    Rep Power
    10
    Quote Originally Posted by RiiStar View Post
    Seems that function searches for a single value?
    Yeah, but you can extend it for any type of data (I used this methods in DarkBOI for finding array of bytes in memory)
    Quote Originally Posted by RiiStar View Post
    Would seeing the orginal function in C++ be helpful?
    You can post it, we can check it But anyways, did you traced delphi code under debugger?
    Please, post your questions on forum, not by PM or mail

    I spend my time, so please pay a little bit of your time to keep world in equilibrium

  8. #8
    RiiStar
    RiiStar is offline
    New member
    Join Date
    2011 Jun
    Posts
    17
    Thanks Thanks Given 
    0
    Thanks Thanks Received 
    1
    Thanked in
    1 Post
    Rep Power
    0
    I started a new job today so no not yet, I'll run it through Olly shortly - though my friend is a lot better at debugging with olly than myself.

    As for the C++ function, i need my friend to send the original to me again since i lost it when my last PC fried itself.

  9. #9
    Dwar
    Dwar is offline
    Veteran Dwar's Avatar
    Join Date
    2010 Mar
    Posts
    2,222
    Thanks Thanks Given 
    211
    Thanks Thanks Received 
    2,230
    Thanked in
    292 Posts
    Rep Power
    10
    Em, one more question: if you write app in C++, if you already have a working function, so why are you trying to port piece of code into delphi?
    Please, post your questions on forum, not by PM or mail

    I spend my time, so please pay a little bit of your time to keep world in equilibrium

  10. #10
    RiiStar
    RiiStar is offline
    New member
    Join Date
    2011 Jun
    Posts
    17
    Thanks Thanks Given 
    0
    Thanks Thanks Received 
    1
    Thanked in
    1 Post
    Rep Power
    0
    I used Delphi for a number of years, i would say i am better at delphi than C++

    Recently my friend started using delphi and liked the language, so we thought it would be an interesting project to create a new patching lib using delphi instead. We didn't know what method to try and use to search the apps memory for an array of bytes like we would do in C++ for patches so i decided since the function in C++ worked i would try to port it to delphi and see if it would work for us.

    As you can see I've failed, which is why since i found your tuts etc very informative i would ask here for your advice.

    I'm trying to analyze it with Olly atm, I'll tell you what i can.
    Currently it's getting so far and crashing the game it's loaded into (that's not good huh?).

    Edit:

    It's loaded pretty early, and it crashes immediately so i can't catch much in Olly.
    Probably need a better break point.

    I might try using the function in a Delphi exe project rather than a DLL and see what i can get from the IDE debugger...
    It's late where i live, i'll try this tomorrow.

    Appreciate the help Dwar!
    Last edited by RiiStar; 2011-09-26 at 10:27 AM.

Page 1 of 3 123 LastLast

Similar Threads

  1. [Tutorial] How to search base address of Aika
    By codename209 in forum Aika Guides, Tutorials
    Replies: 22
    Last Post: 2012-02-22, 12:16 PM
  2. [Hack] Console Function
    By Dwar in forum CrossFire Hack
    Replies: 2
    Last Post: 2011-03-14, 02:20 AM
  3. [Memory Scanner] Memory Hacking Software
    By Dwar in forum Files & Tools
    Replies: 3
    Last Post: 2010-11-29, 03:39 PM
  4. [Question] Finding a function
    By warbeak1245 in forum General Game Research
    Replies: 0
    Last Post: 2010-11-26, 08:15 PM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •