Exetools  

Go Back   Exetools > General > Source Code

Notices

Reply
 
Thread Tools Display Modes
  #1  
Old 09-18-2021, 02:01
countryboy countryboy is offline
Friend
 
Join Date: Sep 2021
Location: in the country
Posts: 22
Rept. Given: 0
Rept. Rcvd 16 Times in 9 Posts
Thanks Given: 32
Thanks Rcvd at 87 Times in 20 Posts
countryboy Reputation: 16
Smile PASCAL - Wild Char Pattern Search for Search & Patch Activation

PASCAL SOURCE CODE USED IN INNO SETUP FOR : countryboy's SEARCH & PATCH ACTIVATION

FORUM STRIPS SPACES FROM POST : HERE IS AN EASIER TO UNDERSTAND IMAGE : THE IMAGE WAS BEFORE BUG FIX & CODE CHANGED TO : ( WHILE i <= (BytesRead - Str2FindLen) DO )

--------------------------------------------------------------------------
// Function GetHexFilePos(PatchNumber, Occurance: Integer; File2Search, FindThis, Pattern: String): Longint;
// Search File2Search for Occurance of Pattern containing Wild Char, and FindThis to get FindThis Position.
// PatchNumber is displayed in Progress Window. Occurance is desired Count of Pattern wanted.
// ?? is Wild Char used in HexCode Pattern, but Not 1st, or Last Char ... FindThis can't contain Wild Char
// String Function POS is used to find longest part of Pattern containing NO WILD CHAR in the Buffer Read.
// If not found then Next Buffer is Read with an overlap := Length of NO WILD STRING - 1 := missed it by 1.
// If NoWild found OK, but Pattern End in Next Buffer then Buffer Position moved forward to Pattern Start.
// If NoWild found OK, but Pattern Start in Previous Buffer then Buffer Pos moved back to Pattern Start.
// If 1st, Mid, & Last Char of Pattern match then LOOP to check if all Char of Pattern Found, and move on.
// If Desired Pattern Occurance Found then Flag is Set. If FindThis in Pattern then File Position is Returned.

Function GetHexFilePos(PatchNumber, Occurrence : Integer; File2Search: String; FindThis: String; Pattern: String): Longint;
VAR
Sfile : TFileStream;
Buffer : Ansistring;
File2Patch, Str2Find, NoWildStr,
FindThisStr, PatchNumStr, FileMsg : String;
Char1, MidChar, EndChar : Char;
BufSize, BytesRead, BufStartPos,
NoWildPos, ThisPos, Str2FindLen,
NoWild2Start, NoWild2End, MidPos,
NextPattern, i, j, k : Longint;
PatternFlag : Boolean;
ProgressPage : TOutputProgressWizardPage;
BEGIN
If (Pattern = '') Then Str2Find := HexStr2ByteStr(FindThis) // IF PATTERN NOT PROVIDED: USE FindThis
Else Str2Find := HexStr2ByteStr(Pattern); // ELSE CONVERT PATTERN TO BINARY WITH ???
FindThisStr := HexStr2ByteStr(FindThis); // CONVERT FindThis TO BINARY STRING
While Str2Find[1] = '?' Do Delete(Str2Find, 1, 1); // DELETE ? FROM START OF PATTERN STRING
While Str2Find[Length(Str2Find)] = '?' Do Delete(Str2Find,Length(Str2Find),1); // DELETE ? FROM END LENGTH OF PATTERN STRING
Str2FindLen := Length(Str2Find); // GET LENGTH OF PATTERN STRING TO SEARCH FOR
If Str2FindLen >= 2 Then MidPos := Str2FindLen Div 2 Else MidPos :=1; // GET MIDDLE OF Pattern IF MORE THAN 2 CHAR
While (MidPos < Str2FindLen) And (Str2Find[MidPos] = '?') Do // FIND A MIDDLE CHAR THAT IS NOT = ?
MidPos := MidPos + 1; // CONTINUE UNTILL NOT WILDCHAR := '?'
MidChar := Str2Find[MidPos]; // GET THE MIDDEL CHAR OF PATTERN : Str2Find
EndChar := Str2Find[Str2FindLen]; // GET LAST CHAR OF PATTERN : NO ?
Char1 := Str2Find[1]; // GET 1ST CHAR IN PATTERN STRING : NO ?

NoWildStr := GetLongestNoWildStr(Str2Find); // LONGEST STRING IN PATTERN WITH NO WILDCHAR : = ?
NoWild2Start := Pos(NoWildStr, Str2Find)-1; // COUNT TO SUBSTRACT FROM NoWildPos TO FIND START POS
NoWild2End := (Str2FindLen - NoWild2Start)-1; // COUNT TO ADD TO NoWildPos TO FIND END POSSITION
PatternFlag := False; // SET FLAG : FOUND DESIRED OCCURANCE OF PATTERN
NextPattern := 0; // OCCURANCE FOUND COUNT OF PATTERN
Result := 0; // FUNCTION RETURN : This FILE POSITION := 0 NOT FOUND

If ShowSearchFileName Then File2Patch := ExtractFileName(File2Search) // SHOW FileName IN PROGRESS WINDOW IF VARIABLE SET
Else File2Patch := '';
FileMsg := expandconstant('{cm:Searching}' +' '+ '{cm:File}' ) + // SHOW SEARCHING FILE + File2Patch
Format(' : %.2d ... ',[FilesSearched +1])+ File2Patch; // GLOBAL 0 BASED INCREMENTED AFTER SEARCH
If PatchNumber <> 0 Then PatchNumStr := expandconstant( // SHOW CUSTOM LANGUAGE PATCH NUMBER IN PROGRESS WINDOW
'{cm:Patch}' +' '+ '{cm:number}'+ Format(' : %.2d ... ',[PatchNumber]))
else PatchNumStr := '';
Try
Sfile := TFileStream.Create(File2Search, FmOpenRead Or FmShareDenyNone); // CREATE FILE OBJECT, AND OPEN FILE : File2Search
BufSize := 31744; // BUFFER SIZE: MAX Integer SIZE := 32768 - 1024
SetLength(Buffer, BufSize); // SET BUFFER SIZE - GET MEMORY
Try
ProgressPage := CreateOutputProgressPage(expandconstant('{cm:Patching}' + // CREATE PROGRESS PAGE CUSTOM LANGUAGE MESSAGE
' '+ '{cm:Program}'+' : ') + aName, expandconstant('{cm:Searching}'+' ...'));
ProgressPage.Hide;
ProgressPage.SetText(FileMsg, PatchNumStr);
ProgressPage.Show;

WHILE (Sfile.Position < (Sfile.Size - Str2FindLen)) Do // SEARCH TO FILE END - LENGTH OF PATTERN
BEGIN
BufStartPos := Sfile.Position; // SAVE BUFFER START: CURRENT - File Position
BytesRead := Sfile.Read(Buffer,BufSize); // FILL BUFFER, AND GET COUNT OF BYTES READ
ProgressPage.SetProgress(Sfile.Position, Sfile.Size - Str2FindLen); // SHOW PROGRESS
If BytesRead < Str2FindLen Then Break; // NOT ENOUGH BYTES READ FOR PATTERN LENGTH
NoWildPos := Pos(NoWildStr, Buffer); // USE STRING POSITION FUNCTION TO FIND NoWildStr
If (NoWildPos > 0) Then // FOUND NoWild PART OF PATTERN IN THIS BUFFER
BEGIN
If (NoWild2Start > NoWildPos) OR // PATTERN START IN PREVIOUS BUFFER OR
(NoWildPos + NoWild2End > BytesRead) Then // PATTERN END IN NEXT BUFFER
Begin
If NoWild2Start > NoWildPos then // PATTERN START IN LAST BUFFER NoWildPos - NoWild2Start
Sfile.Position := BufStartPos - NoWild2Start; // SET BUFFER START POSITION BACK - NoWild2Start
If NoWildPos + NoWild2End > BytesRead Then // PATTERN END NOT IN THIS BUFFER
Sfile.Position := (BufStartPos + NoWildPos) - Str2FindLen; // MOVE BUFFER START FORWARD TO POS BEFORE Str2Find Start
BufStartPos := Sfile.Position; // SAVE BUFFER START: File Position
BytesRead := Sfile.Read(Buffer,BufSize); // REREAD BUFFER - GET COUNT OF BYTES READ
NoWildPos := Pos(NoWildStr, Buffer); // GET POSITION OF NoWildStr IN BUFFER
End;
i := NoWildPos - NoWild2Start; // i := START OF 1ST CHAR IN PATTERN STRING
WHILE i <= (BytesRead - Str2FindLen) DO // WHILE LOOP ( CARRY OVER FROM OLD SEARCH ENGINE )
BEGIN // i SHOULD = 1ST CHAR ( NoWildPos - NoWild2Start )
PatternFlag := false; // NOT found YET !
If (Buffer[i] = Char1) And (Buffer[i+MidPos-1] = MidChar) And // IS 1st CHAR, AND MIDDLE CHAR OF PATTERN IN BUFFER
(Buffer[i + Str2FindLen-1] = EndChar) Then // NOW CHECK IF LAST CHAR OF Pattern FOUND.
BEGIN // OK, NOW CHECK IF ALL CHAR ARE IN BUFFER
j := i; // START AT 1st CHAR OF Str2Find
For k := 1 to Str2FindLen Do // CHECK IF ALL CHAR OF Str2Find IN BUFFER
Begin
if (Buffer[j] <> Str2Find[k]) then // IF NOT FOUND :
if (Str2Find[k] <> '?') then Break; // CHECK IF WILDCHAR, OR BREAK k LOOP IF NOT ?
j := j + 1 // CONTINUE : CHECK NEXT CHAR IN BUFFER.
End; // END OF k LOOP.
If k > Str2FindLen then // FOUND IT: STAYED IN k LOOP TO END OF STRING.
Begin // FIND DESIRED OCCURANCE OF PATTERN.
NextPattern := NextPattern + 1; // INCREMENT THE FOUND COUNT.
If (NextPattern >= Occurrence) then // IF DESIRED OCCURANCE FOUND Then SET FLAG, and BREAK.
Begin
PatternFlag := true; // FOUND : The WHOLE STRING Str2Find IN Buffer
Break; // FOUND: BREAK i LOOP : Str2Find IN BUFFER
End; // END : If (NextPattern >= Occurrence)
End; // END : If k > Str2FindLen
END; // END: IF (Buffer[i] = Str2Find[1])
i := i + 1; // CONTINUE NEXT BUFFER CHAR
END; // END: ( while i <= BytesRead )
END ELSE i := BufSize - length(NoWildStr); // END If (NoWildPos > 0) OVERLAP NEXT BUFFER READ
Sfile.Position := (BufStartPos + (i-1)); // ADD BYTES SEARCHED in Buffer TO FILE POSITION 1 based
ProgressPage.SetProgress(Sfile.Position, Sfile.Size); // SHOW PROGRESS
If PatternFlag Then // FOUND: Str2Find PATTERN OCCURANCE IN BUFFER
Begin
BytesRead := Sfile.Read(Buffer,Str2FindLen); // READ Str2Find IN BUFFER, and get count of bytes read
ThisPos := (Pos(FindThisStr, Buffer)); // ThisPos := POSITION OF FindThis IN BUFFER PATTERN
If ThisPos > 0 Then // IF FindThis FOUND IN PATTERN IN BUFFER
Begin
ThisPos := ThisPos - 1 // Change 1 base to 0 Based File Postition
Result := (BufStartPos + i-1 + ThisPos); // RETURN FILE OFFSET OF THIS
End Else Result := 0; // SET NOT FOUND IF FindThis NOT FOUND
Break; // BREAK WHILE (Sfile.Position < ) LOOP FOUND Str2Find
End Else Result := 0; // SET NOT FOUND IF NO PATTERN FLAG
If BytesRead < Str2FindLen Then Break; // ERROR: Fixed - Last Buffer break out:
END; // END OF WHILE (Sfile.Position < ) LOOP
If Result <> 0 Then ProgressPage.SetText(FileMsg, PatchNumStr + FoundMsg) // CODE FOUND: CUSTOM LANGUAGE TRANSLATION MESSAGE
Else ProgressPage.SetText(FileMsg, PatchNumStr + NotFoundMsg); // SHOW CUSTOM LANGUAGE TRANSLATION NOT FOUND MESSAGE
Sleep(SearchMsgWaitTime); // GLOBAL WAIT TIME IN MILISECONDS TO VIEW FOUND MESSAGE
Finally Sfile.Free end; // FREE FILE OBJECT's MEMORY ON HEAP
SetLength(Buffer, 0); // FREE BUFFER MEMORY
Finally ProgressPage.Hide; end; // HIDE THE PROGRESS PAGE
END;

Just fixed a bug where a very long search Pattern missed the last byte :
Quote:
Quote:
OLD INSTRUCTION : WHILE i < (BytesRead - Str2FindLen) DO

CHANGED TO: WHILE i <= (BytesRead - Str2FindLen) DO
1 PATTERN USED TO PATCH 59 Files with 196 Patches ...
Quote:
THIS IS THE PATTERN THAT CREATED AN ERROR IF THE PATTERN WAS 1 BYTE LONGER.
THIS IS 1 OF THE PATTERNS USED TO CRACK FlexLm Software protection in ToonBoom Harmony v21
IF THE SEARCH PATTERN INCLUDED C4 ON END THEN IT WAS NOT FOUND.
IF C4 WAS REMOVED THEN THE CODE WAS FOUND ... Above change Fixed Bug.

THE PROCEDURE BELOW IS A POINTER FOR A FILE IN A LIST OF PROCEDURES TO CALLS TO PATCH ...

Procedure Search_lmgrd_exe();
Begin //......[ FINDTHIS ]....................... [ PATTERN ] .........................,... [ NEWHEX ] .. [ COMMENTS ]
FindAndPatch('418BC6' ,'418BC6488B??????00004833CCE8????????4881C4' , '31 C0 90' ) ; // lea r8, a_lic ; ".lic" REMOVE C4 ON SEARCH to find it !
End;
SHORTER PATTERN LENGTH := FASTER SEARCH TIME
70 Files - 320 Patches : Search Time := 39 Seconds
Code:
PATTERNS USED IN : Toon Boom_Harmony 20.0.3.16743 Activation
Search & Patch ACTIVATION :https://mir.cr/JOMBDHA0
Harmony Premium 20.0.3.16743 SETUP
LONGER PATTERN LENGTH := SLOWER SEARCH TIME
59 Files - 196 Patches ... 01 Minutes, 46 Seconds
Code:
PATTERNS USED IN : Toonboom Harmony Premium 21.0.0.17367 Activation
ACTIVATION : https://mir.cr/AXV5GY4L
Toonboom Harmony Premium 21.0.0.17367 SETUP
THE LONG LENGTH OF THE NUMBER 4 PATCH PATTERN LISTED ABOVE TOOK THE LONGEST TIME TO FIND !
THE SEARCH PATTERN WAS IN 24 FILES The 1 BYTE TOO LONG : Bug was fixed after the Release !


If anyone sees a possible bug, or has any ideas on CODE IMPROVEMENT FOR A FASTER PATTERN SEARCH THEN I'am Interested.

Have a great day, countryboy

***************************************************************************************************************************

SUPPORT FUNCTIONS CALLED BY PATTERN SEARCH ENGINE ..

Quote:
; Pascal Code used in ANSI Version of Inno Setup ... search 36 Files with a total of 286 Searches in 35 Seconds. ...
; Released to Public Domain by @ countryboy

[Setup]
; ADD FOLLOWING LINE : IF CUSTOM MESSAGES IN EXTERNAL FILE ...
#include "CustomMessages.iss"

[CustomMessages]
english.Searching=Searching
english.Patching=Patching
english.Program=Program
english.Code=Code
english.NOT=NOT
english.Found=Found
english.Patch=Patch
english.number=number
english.File=File

[CODE]

CONST
aName = 'Name of Program to Activate';
ShowSearchFileName = True; // SHOW FILE NAME ON SEARCH PROGRESS MENU
SearchMsgWaitTime = 50; // PATTERN SEARCH MESSAGE WAIT TIME IN Milliseconds

Function FoundMsg() : String; //CUSTOM LANGUAGE MESSAGE
begin
Result := expandconstant('{cm:Found}' +' ... ');
end;

Function NotFoundMsg() : String; // CUSTOM LANGUAGE MESSAGE
begin
Result := expandconstant('{cm:NOT}' +' '+ '{cm:Found}' +' ... ');
end;

Function HexStr2ByteStr(HexString: String) : String;
Var i : Integer; s, BinStr : string; c : char;
Begin
i := 1;
s := '';
While i <= Length(HexString) Do
Begin
If HexString[i] <> ' ' Then s := s + HexString[i];
i := i + 1;
End;
i:=1;
BinStr := '';
While i < Length(s) Do
Begin
If ((s[i] <> '?') And (s[i+1] <> '?')) Then
Begin
c := Chr(StrToIntDef('$' + Copy(s,i,2),0));
BinStr := BinStr + c;
End Else BinStr := BinStr + '?';
i := i + 2;
End;
Result := BinStr;
End;

Function GetLongestNoWildStr(S: AnsiString) : AnsiString;
var i : Integer; s2: AnsiString;
Begin
Result := '';
For i := 1 to Length(S) Do
Begin
s2 := '';
While (i <= Length(S)) And (S[i] <> '?') Do
Begin
s2 := s2 + S[i];
i := i + 1;
End;
If length(s2) > length(Result) Then Result := s2;
End;
End;
PART OF TUTORIAL FROM A CGPersia POST :

Quote:
Interested in Programing, and Cracking, or need a Fast Pattern Search Function for your Patch Engine ?

Normally I would post this in the Reversing Forum, but some Folks interested in Programing may not have access.
Updated my Pattern Search Engine to add Custom Language Messages, and decided to also update the Pattern Search Function.
If you used my Harmony Pattern Search of 33 Files that toke 20 to 25 minutes to Search 33 Files then you know it was slow.
The new Pattern Search can search a 100 meg File in Seconds, and could possibly search all 36 Harmony Files in less than 1 Minute ...

WHAT IS A WILD CHAR PATTERN SEARCH ?
Assembly Language use 2 part instructions with part of the Instruction being a memory offset Address.
When a program is recompiled the address offsets part of a Instruction change.
The address part of Hex Instruction is replaced with ?? to create a Pattern to find Instruction in the New Compiled Code.

I program in about a half dozen Languages, but I love Pascal because of English like, and easy to Visualize Logic of writing Code to accomplish a Task.
Want to type less then convert it to C++ by changing the { Begin End } to {}, and ( i := i + 1); TO ( i++ ) and that's why it's called C++
Make sure C++ Code is well commented, or years later it looks like an Algebra Formula when trying to figure out you own Logic.

WHAT IS THE DIFFERENCE BETWEEN ANSI AND UNICODE ?
ANSI : A standard that uses a long String. C++ Strings are only terminated with 00 at end of String.
UNICODE : Every Character, or Byte of String is Terminated with a 00 ... The Size doubles.
In Pascal, 1st Char of String is the Length. In C++ You have to search to string end to find the length.
C ++ may also use Pascal calling conventions on Passing Parameters on the Stack.
If you Write a patch to disk using UNICODE then the File is corrupted by writing a 00 zero after every byte written.

CRACKERS EXPERIENCE TO REMEMBER !
Write your Code in Language of Choice, and load it into the Debugger to see what needs to be done to rewrite it as Assembly Language to speed it up.
Program Language Compilers insert SNIPPETS of CODE for the If Then Else Statements, and sometimes they even Flip the Script.
Crackers should be familiar with QuickTime Library Code Snippets used, and seen in a large majority of Programs released these days.

KNOWING PROGRAMING HELPS WITH CRACKING !
While debugging a program, Crackers see the Logic of how the Code works, and it's a lot easier if you understand what the Code is doing.

LOGIC OF WRITING CODE :
If you can follow, and understand the following Code then you may become good at Programing, or Cracking.
Haven't done a lot of Programing lately, and probably have a lot of spelling Errors, but
If you see Errors in my Logic as to the process of Searching a File to find a Wild Char Pattern then let me know.
UPDATE : THE FOLLOWING CODE CHANGES HAVE BEEN MADE : - Updated on 9/20/2021
ORIGINAL : WHILE i < (BytesRead - Str2FindLen) DO // WHILE LOOP ( CARRY OVER FROM OLD SEARCH ENGINE )
CHANGED : WHILE i <= (BytesRead - Str2FindLen) DO // WHILE LOOP ( CARRY OVER FROM OLD SEARCH ENGINE )
REASON . : BUG : MISSED PATTERN - IF PATTERN WAS 1 BYTE TO LONG.

ORIGINAL : Sfile.Position := (BufStartPos + NoWildPos) - Str2FindLen; // MOVE BUFFER START FORWARD TO POS BEFORE Str2Find Start
CHANGED : Sfile.Position := (BufStartPos + NoWildPos) - NoWild2Start; // MOVE BUFFER START FORWARD TO POS OF Str2Find Start
REASON . : MOVED BUFFER TO START OF Str2Find : not before, but exact position DIFFERENCE IS ( Str2FindLen = NoWildPos ) bytes moved ahead.


Have a great day, countryboy

Last edited by countryboy; 09-21-2021 at 07:32.
Reply With Quote
The Following User Says Thank You to countryboy For This Useful Post:
Mendax47 (09-18-2021)
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is On



All times are GMT +8. The time now is 12:20.


Always Your Best Friend: Aaron, JMI, ahmadmansoor, ZeNiX
( 1998 - 2021 )