source: tools/wow_patcher/wowpatcher.pas

Last change on this file was 491, checked in by george, 14 years ago
  • Přidáno: Kontrola existence znaku $cc za sekvencí a čtveřicí adres.
File size: 6.7 KB
Line 
1program wowpatcher;
2
3{$mode objfpc}{$H+}
4
5uses
6 {$IFDEF UNIX}{$IFDEF UseCThreads}
7 cthreads,
8 {$ENDIF}{$ENDIF}
9 Classes, SysUtils, CustApp
10 { you can add units after this };
11
12const
13 Version = '1.2';
14 ReleaseDate = '2010-09-08';
15
16type
17
18 { TPatcher }
19
20 { TWoWPatcher }
21
22 TWoWPatcher = class(TCustomApplication)
23 private
24 function FindSequence(Data: array of Byte; Sequence: array of Integer; Position: Integer = 0): Integer;
25 procedure WriteHexData(Data: array of Integer; From, Count: Integer);
26 procedure WriteHexData(Data: array of Byte; From, Count: Integer);
27 protected
28 procedure DoRun; override;
29 public
30 FileName: string;
31 NewFileName: string;
32 constructor Create(TheOwner: TComponent); override;
33 destructor Destroy; override;
34 procedure WriteHelp; virtual;
35 procedure Patch;
36 end;
37
38{ TWoWPatcher }
39
40procedure TWoWPatcher.DoRun;
41begin
42 WriteLn('wowpatcher ' + Version + ' ' + ReleaseDate);
43 if HasOption('h', 'help') then begin
44 WriteHelp;
45 Terminate;
46 Exit;
47 end;
48 if HasOption('s', 'source') then begin
49 FileName := GetOptionValue('s', 'source');
50 end;
51
52 NewFileName := Copy(FileName, 1, Length(FileName) -
53 Length(ExtractFileExt(FileName))) + '-2' + ExtractFileExt(FileName);
54 Patch;
55
56 Terminate;
57end;
58
59constructor TWoWPatcher.Create(TheOwner: TComponent);
60begin
61 inherited Create(TheOwner);
62 StopOnException := True;
63 FileName := 'Wow.exe';
64end;
65
66destructor TWoWPatcher.Destroy;
67begin
68 inherited Destroy;
69end;
70
71procedure TWoWPatcher.WriteHelp;
72begin
73 Writeln('Usage: ', ExtractFileName(ExeName));
74 WriteLn(' -s source Select Wow.exe source file');
75 WriteLn(' -h help Show this help');
76 WriteLn;
77 WriteLn('Patched exe file cannot be used safely on offical servers.');
78end;
79
80function TWoWPatcher.FindSequence(Data: array of Byte; Sequence: array of Integer; Position: Integer = 0): Integer;
81var
82 I: Integer;
83 II: Integer;
84 Same: Boolean;
85begin
86 if Length(Sequence) = 0 then
87 raise Exception.Create('Empty searched sequence');
88 Result := -1;
89 for I := Position to Length(Data) - Length(Sequence) do begin
90 if Data[I] = Sequence[0] then begin
91 Same := True;
92 for II := 0 to High(Sequence) do begin
93 if (Sequence[II] <> -1) and (Data[I + II] <> Sequence[II]) then begin
94 Same := False;
95 Break;
96 end;
97 end;
98 if Same then begin
99 Result := I;
100 Break;
101 end;
102 end;
103 end;
104end;
105
106procedure TWoWPatcher.WriteHexData(Data: array of Integer; From, Count: Integer);
107var
108 I: Integer;
109begin
110 for I := From to From + Count - 1 do
111 if Data[I] <> -1 then
112 Write(IntToHex(Data[I], 2) + ' ')
113 else Write('XX ');
114end;
115
116procedure TWoWPatcher.WriteHexData(Data: array of Byte; From, Count: Integer);
117var
118 I: Integer;
119begin
120 for I := From to From + Count - 1 do
121 Write(IntToHex(Data[I], 2) + ' ');
122end;
123
124procedure TWoWPatcher.Patch;
125var
126 OriginalFile: TFileStream;
127 NewFile: TFileStream;
128 Buffer: array of Byte;
129 Position: Integer;
130 I: Integer;
131 Shift: Integer;
132 NotValid: Boolean;
133const
134 // -1 means any byte value
135 StartSequence: array[0..15] of Integer = ($8D, $4D, $E8, $E8, -1, -1, -1, -1, $5B, $8B, $E5, $5D, $C3, $8D, $49, $00);
136 StartSequence2: array[0..15] of Integer = ($88, $1D, -1, -1, -1, -1, $E8, -1, -1, -1, -1, $5B, $8B, $E5, $5D, $C3);
137begin
138 if not FileExists(FileName) then begin
139 WriteLn(Format('File %s not found', [FileName]));
140 Exit;
141 end;
142 try
143 OriginalFile := TFileStream.Create(FileName, fmOpenRead);
144 SetLength(Buffer, OriginalFile.Size);
145 OriginalFile.Read(Buffer[0], Length(Buffer));
146 finally
147 OriginalFile.Free;
148 end;
149
150 WriteLn;
151 Write('Searching for first sequence ');
152 WriteHexData(StartSequence, 0, Length(StartSequence));
153 Write('...');
154 Position := FindSequence(Buffer, StartSequence, 0);
155 if Position <> -1 then begin
156 WriteLn('found at ' + IntToHex(Position, 8));
157 Inc(Position, Length(StartSequence));
158 if FindSequence(Buffer, StartSequence, Position) <> -1 then
159 WriteLn('Multiple occurence found - ambiguous')
160 else begin
161 Shift := 0;
162 repeat
163 NotValid := False;
164 for I := 0 to 3 do
165 if Buffer[Position + Shift + 3 + I * 4] <> 0 then NotValid := True;
166 if Buffer[Position + Shift + 3 + 4 * 4] <> $cc then NotValid := True;
167 if NotValid then Inc(Shift);
168 if Shift > 100 then begin
169 WriteLn('No valid data found after sequence');
170 Exit;
171 end;
172 until not NotValid;
173 if Shift > 0 then WriteLn('Data shift after sequence: ' + IntToStr(Shift));
174 Position := Position + Shift;
175
176 WriteLn('Changing data after sequence');
177 WriteHexData(Buffer, Position, 16);
178 for I := 0 to 11 do
179 Buffer[Position + I] := Buffer[Position + 12 + (I mod 4)];
180 WriteLn(' => ');
181 WriteHexData(Buffer, Position, 16);
182 end;
183 WriteLn;
184 end else begin
185 WriteLn('not found');
186 Exit;
187 end;
188
189 WriteLn;
190 Write('Searching for second sequence ');
191 WriteHexData(StartSequence2, 0, Length(StartSequence2));
192 Write('...');
193 Position := FindSequence(Buffer, StartSequence2);
194 if Position <> -1 then begin
195 WriteLn('found at ' + IntToHex(Position, 8));
196 Inc(Position, Length(StartSequence2));
197 if FindSequence(Buffer, StartSequence2, Position) <> -1 then begin
198 WriteLn('Multiple occurence found - ambiguous')
199 end else begin
200 Shift := 0;
201 repeat
202 NotValid := False;
203 for I := 0 to 3 do
204 if Buffer[Position + Shift + 3 + I * 4] <> 0 then NotValid := True;
205 if Buffer[Position + Shift + 3 + 4 * 4] <> $cc then NotValid := True;
206 if NotValid then Inc(Shift);
207 if Shift > 100 then begin
208 WriteLn('No valid data found after sequence');
209 Exit;
210 end;
211 until not NotValid;
212 if Shift > 0 then WriteLn('Data shift after sequence: ' + IntToStr(Shift));
213 Position := Position + Shift;
214
215 WriteLn('Changing data after sequence');
216 WriteHexData(Buffer, Position, 16);
217 for I := 0 to 11 do
218 Buffer[Position + I] := Buffer[Position + 12 + (I mod 4)];
219 WriteLn(' => ');
220 WriteHexData(Buffer, Position, 16);
221 end;
222 WriteLn;
223 end else begin
224 WriteLn('not found');
225 Exit;
226 end;
227
228 try
229 WriteLn(Format('Patched file %s created', [NewFileName]));
230 NewFile := TFileStream.Create(NewFileName, fmCreate);
231 if Length(Buffer) > 0 then
232 NewFile.WriteBuffer(Buffer[0], Length(Buffer));
233 finally
234 NewFile.Free;
235 end;
236end;
237
238var
239 Application: TWoWPatcher;
240
241{$R wowpatcher.res}
242
243begin
244 Application := TWoWPatcher.Create(nil);
245 Application.Title := 'WoW patcher';
246 Application.Run;
247 Application.Free;
248end.
249
Note: See TracBrowser for help on using the repository browser.