Page 1 of 2

How to search HEX value and replace all it

Posted: Mon Jun 24, 2024 10:17 am
by hoangdiemtinh
I am new to PB. My primary language is not US/UK. I am using Google Translate.

I need to create a patch for a file.
I have the hex code from the following Procedure.

How to find all these HEX value and replace them in one file?

Re: How to search HEX value and replace all it

Posted: Mon Jun 24, 2024 10:21 am
by BarryG
Your post history is VERY concerning.

Re: How to search HEX value and replace all it

Posted: Mon Jun 24, 2024 10:38 am
by hoangdiemtinh
I replaced the same hex value (in my exe file) by using HxD Hex Editor.
But I want to automate this operation, it happens faster.

Re: How to search HEX value and replace all it

Posted: Mon Jun 24, 2024 10:53 am
by PBJim
BarryG wrote: Mon Jun 24, 2024 10:21 am Your post history is VERY concerning.
Agreed, I’ve been increasingly concerned, particularly with all the global news of state-sponsored attacks on systems and infrastructure, which human rights-abusing regimes we’re in fact helping to support by giving powerful working PB code and functions. In fact, the writer of the linked post to which the OP refers, also asked several days ago about the ability to disable an important Windows anti-malware security feature. I’m mindful that PureBasic’s architecture, gives it a great deal of power to do harm, as well as good, in comparison with some of the competing languages that are encumbered by Common Language Infrastructure and so on.

Re: How to search HEX value and replace all it

Posted: Mon Jun 24, 2024 7:45 pm
by infratec
You don't nee a hex code to replace a byte or a sequence of bytes.
You can do it directly in the memory which is much faster.

Btw. you didn't told us what you want to replace with what.

Re: How to search HEX value and replace all it

Posted: Mon Jun 24, 2024 11:22 pm
by hoangdiemtinh
Is it possible to replace it with a hex segment whose length is smaller or larger than the found hex segment?
(If this is not possible, just use the equal length option.)

ex:
hex to find: 66696e642069742e
hex to replace: 666f756e642069742e

Hex code is converted from utf-8 string.

Re: How to search HEX value and replace all it

Posted: Tue Jun 25, 2024 4:58 am
by infratec
Is is correct that he stings have not the same length?

If you really want to replace strings, why not ReplaceString() ?

Re: How to search HEX value and replace all it

Posted: Tue Jun 25, 2024 9:06 am
by hoangdiemtinh
Have the same byte length.
( If possible, in case the byte length to replace is greater than the original byte length, insert 00 or FF ).
The file (.exe, .dll...) to find replacement bytes is made with unicode support.

Re: How to search HEX value and replace all it

Posted: Tue Jun 25, 2024 9:47 am
by mk-soft
HEX values are only one form of representation. So there will be no HEX in the file (unless someone has stored them as text in the file for fun)
It is therefore an array of bytes and can be edited with ReadByte and WriteByte in the file.
Then you can think about how this display. (HEX, OCT, DEC, CHAR, BIN)

Code: Select all

Structure ArrayOfByte
  StructureUnion
    b.b[0] ; -128 .. 128
    a.a[0] ; 0 .. 255
  EndStructureUnion
EndStructure

Re: How to search HEX value and replace all it

Posted: Tue Jun 25, 2024 11:25 am
by hoangdiemtinh
Searched the forum, I saw a post by @CELTIC88

I tried running it but got an error:

Code: Select all

ScrollBarGadget(): ScrollBar 'PageLength' must be lower than or equal to the 'Max' value.
and it's long for me to understand...

Re: How to search HEX value and replace all it

Posted: Tue Jun 25, 2024 1:05 pm
by boddhi
hoangdiemtinh wrote: and it's long for me to understand...
:shock:
 
Programming does require a bit of analysis, research and testing. :wink:

Code: Select all

ScrollBarGadget(#PB_Any, Width + x, y, 15, Height, 0, 0, 1,#PB_ScrollBar_Vertical)
PureBasic debug wrote:[...] 'PageLength' MUST BE LOWER THAN OR EQUAL to the 'Max' value
PureBasic help wrote:Result = ScrollBarGadget(#Gadget, x, y, Width, Height, Minimum, Maximum, PageLength [, Flags])
So, what are the values of these two parameters?
0, 1,#PB_ScrollBar_Vertical
Try to change these values to see what it happens!

Re: How to search HEX value and replace all it

Posted: Tue Jun 25, 2024 2:10 pm
by hoangdiemtinh
Why not success ? ( Source at here )

Code: Select all

EnableExplicit

#REPLACEONE     = 1 ;make only one replacement, default is to search whole file and make multiple replacements (without this flag)
#STRINGMODE     = 2 ;find string, default is hex (without this flag)
#CASESENSITIVE  = 4 ;case sensitive string search and replace, default is case-insensitive  (without this flag)
#FILLDATA       = 8 ;if DataToReplace$ is smaller than DataToFind$ then append data to make it same length as DataToFind$, function returns error (-1) without this flag if DataToFind$ and DataToReplace$ are not same length

#STRING_CASESENSITIVE=#STRINGMODE|#CASESENSITIVE|#FILLDATA

Procedure ReplaceDataInFile(File$, DataToFind$, DataToReplace$, StartPosition=1, Flags=#FILLDATA, BufferLen=4096,*Count=0)
  
  ;RETURN:  <0  if error {-4=file not found;-3=file open error;-2=not enough free memory on system;-1=wrong parameters}
  ;         =0  if ToFind$ not found
  ;         >0  position of last replacement
  
  Protected _ltf=Len(DataToFind$)
  Protected _ltr=Len(DataToReplace$)
  
  Protected length = _ltf
  Protected k, result
  
  If Not Flags & #STRINGMODE  ; if hex search...
    If (length%2)<>0          ; ...then len must be {2,4,6,8,...}
      ProcedureReturn -1    ; we don't have valid len for hex search (1,3,5,7,... is not valid)
    EndIf
    length/2                  ; 2 hex characters means 1 byte
  EndIf
  
  If Flags & #FILLDATA
    If _ltf>_ltr                        ;if length of DataToReplace$ is smaller than DataToFind$...
      DataToReplace$+Space(_ltf-_ltr)   ;...then add empty data (space characters: chr(20)) to end of DataToReplace$
      Protected __ltr=_ltr
      _ltr=Len(DataToReplace$)
      If Not Flags & #STRINGMODE        ;if we do not search for string (--> hex search)...
        For k=__ltr To _ltf-1
          PokeS(@DataToReplace$+k,"0")    ;...then convert spaces to zeros (or instead of "0" to "F")
        Next
      EndIf
    EndIf
  EndIf
  
  If length=0 Or StartPosition=<0 Or _ltf<>_ltr Or BufferLen=<0 Or BufferLen<length Or Flags<0
    ProcedureReturn -1
  EndIf
  
  Protected *searchdata         = AllocateMemory((length*2)+BufferLen)
  Protected *replacedata        = *searchdata+length
  Protected *testdata.Character = *replacedata+length
  
  If *searchdata=0
    ProcedureReturn -2
  EndIf
  
  If Flags & #STRINGMODE   ; if string search...
    If Not Flags & #CASESENSITIVE
      DataToFind$=UCase(DataToFind$)
    EndIf
    PokeS(*searchdata ,DataToFind$)
    PokeS(*replacedata,DataToReplace$)
  Else                    ; if hex search...
    For k=0 To length-1
      PokeB(*searchdata +k,Val("$"+PeekS(@DataToFind$   +(k*2),2)))
      PokeB(*replacedata+k,Val("$"+PeekS(@DataToReplace$+(k*2),2)))
    Next
  EndIf
  
  If FileSize(File$)>=0 ;OpenFile() creates file if it doesn't exist --> we don't want that so we check it before if it exists
    Protected file = OpenFile(#PB_Any, File$) ;if someone deletes file before this line is executed then we create empty file :( but probability of this is so small that we simply ignore it
    If file
      Protected readpos = StartPosition-1
      Protected thiseof = Lof(file) - length
      Protected replacecount = 0
      While (Not Eof(file)) And readpos <= thiseof
        FileSeek(file, readpos)
        
        Protected DataRead=ReadData(file, *testdata, BufferLen)
        If Flags & #STRINGMODE
          If Not Flags & #CASESENSITIVE
            For k=0 To DataRead-1   ;we can't convert it to uppercase at once because it could have chr(0) in the middle so we have this loop
              *testdata\c = Asc(UCase(Chr(*testdata\c)))  ;*testdata\c is a little faster than PeekC()
              *testdata+1 ;optionally: create structure with chr.c[0] and then use *testdata\chr[k] in previous line instead of this
            Next
            *testdata-DataRead    ;return pointer to first byte
          EndIf
        EndIf
        
        ;Debug "Buffered: "+PeekS(*testdata,DataRead)
        
        For k=0 To DataRead-length
          ;Debug "> Test: "+PeekS(*testdata+k,length) + " == " + PeekS(*searchdata,length)
          If CompareMemory(*testdata+k, *searchdata, length)
            FileSeek(file, readpos+k)
            ;Debug "Replacing data..."
            WriteData(file, *replacedata, length)
            result=readpos+k+1  ;save position
            replacecount+1
            If ((DataRead-length)-k)=<length
              readpos+(2*length+k-DataRead-1)
            EndIf
            k+(length-1)        ;skip comparing replaced characters in this loop
            If Flags & #REPLACEONE
              Break 2
            EndIf
          EndIf
        Next
        
        readpos + (DataRead - (length-1))
        
      Wend
      CloseFile(file)
    Else
      result=-3
    EndIf
  Else
    result=-4
  EndIf
  
  FreeMemory(*searchdata)
  
  If *Count<>0
    PokeI(*Count,replacecount)
  EndIf
  
  ProcedureReturn result
EndProcedure

Define counter.i

Global ddd.i = ReplaceDataInFile("E:\my-app.exe", "66696e64206d65", "66696e64207975", 1, #FILLDATA, 4096, @counter)
Debug ddd

Select ddd
  Case -4,-3,-2,-1
    MessageRequester("Error","Procedure failed!",#MB_ICONERROR)
  Case 0
    MessageRequester("","No replacements made.")
  Default
    MessageRequester("Success","Number of replacements made: "+Str(counter))
EndSelect




Re: How to search HEX value and replace all it

Posted: Tue Jun 25, 2024 2:44 pm
by Axolotl
<OT>
I really like you guys for trying to help here.
However, I do not understand how help can be provided.
What does it mean when someone is not even willing or able to execute a single command without error?
Programming does require a bit of analysis, research and testing. :wink:

I don't think so any more, as you can easily get help from forums with the support of natural intelligence and (in the near future) artificial intelligence.
I'm sorry, but sometimes I can't help myself. :oops: :mrgreen:
</OT>

Re: How to search HEX value and replace all it

Posted: Tue Jun 25, 2024 4:52 pm
by boddhi
hoangdiemtinh wrote: Tue Jun 25, 2024 2:10 pm Why not success ?
 
Little hint: You need to inspect the way search and replace strings are stored in and retrieved from memory.

Re: How to search HEX value and replace all it

Posted: Wed Jun 26, 2024 6:36 am
by hoangdiemtinh
I found a module ( it's belong to C# ). Please convert it to PB.

Code: Select all

namespace ClassicPatcher
{
    internal class Patch
    {
        private static bool DetectPatch(byte[] sequence, int position, byte[] FindHex)
        {
            if (position + FindHex.Length > sequence.Length) return false;
            for (int p = 0; p < FindHex.Length; p++)
            {
                if (FindHex[p] != sequence[position + p] && FindHex[p] != 0x3F) // Check for wildcard byte 0x3F ('?')
                    return false;
            }
            return true;
        }

        internal static byte[] StringToByteArray(string hex)
        {
            hex = hex.Replace(" ", "");
            int NumberChars = hex.Length;
            byte[] bytes = new byte[NumberChars / 2];
            for (int i = 0; i < NumberChars; i += 2)
            {
                if (hex.Substring(i, 2) == "??")
                    bytes[i / 2] = 0x3F; // Set wildcard byte 0x3F ('?')
                else
                    bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
            }
            return bytes;
        }

        internal static bool PatchFile(string originalFile, string findHex, string patchHex)
        {
            bool b = false;

            if (File.Exists(originalFile))
            {
                byte[] ReplaceHex = StringToByteArray(patchHex);
                byte[] FindHex = StringToByteArray(findHex);
                // Read file bytes.
                byte[] fileContent = File.ReadAllBytes(originalFile);

                // Detect and patch the file.
                for (int p = 0; p < fileContent.Length; p++)
                {
                    if (!DetectPatch(fileContent, p, FindHex)) continue;

                    for (int w = 0; w < ReplaceHex.Length; w++)
                    {
                        b = true;
                        fileContent[p + w] = ReplaceHex[w];
                    }
                }

                File.WriteAllBytes(originalFile, fileContent);

            }

            return b;
        }

        internal static void PatchOffset(string originalFile, string offset, string patchHex)
        {
            byte[] ReplaceHex = StringToByteArray(patchHex);
            int off = Convert.ToInt32(offset, 16);
            // Read file bytes.
            byte[] fileContent = File.ReadAllBytes(originalFile);

            // Detect and patch the file.
            for (int p = 0; p < fileContent.Length; p++)
            {
                //if (p >= off) continue;

                for (int w = 0; w < ReplaceHex.Length; w++)
                {
                    fileContent[off + w] = ReplaceHex[w];
                }
            }

            File.WriteAllBytes(originalFile, fileContent);
        }

        internal static bool PatternExists(string originalFile, string findHex)
        {
            byte[] FindHex = StringToByteArray(findHex);
            // Read file bytes.
            byte[] fileContent = File.ReadAllBytes(originalFile);

            // Detect and patch the file.
            for (int p = 0; p < fileContent.Length; p++)
            {
                if (DetectPatch(fileContent, p, FindHex))
                {
                    return true;
                }
            }

            return false;
        }
    }
}