Skip to content

Commit f2751c7

Browse files
authored
Merge pull request #23 from LittleBigRefresh/fix-rpcs3-patching
Fix various patching issues
2 parents 46d74cf + aa33838 commit f2751c7

File tree

2 files changed

+52
-52
lines changed

2 files changed

+52
-52
lines changed

Refresher/Patching/Patcher.cs

Lines changed: 45 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,16 @@ public Patcher(Stream stream)
3939
/// <returns>A list of the URLs and Digest keys</returns>
4040
private static List<PatchTargetInfo> FindPatchableElements(Stream file)
4141
{
42+
long start = Stopwatch.GetTimestamp();
43+
4244
file.Position = 0;
4345
using IELF? elf = ELFReader.Load(file, false);
4446
file.Position = 0;
4547

46-
BinaryReader reader = new(file);
47-
48+
//Buffer the stream with a size of 4096
49+
BufferedStream bufferedStream = new(file, 4096);
50+
BinaryReader reader = new(bufferedStream);
51+
4852
// The string "http" in ASCII, as an int
4953
int httpInt = BitConverter.ToInt32("http"u8);
5054

@@ -56,65 +60,56 @@ private static List<PatchTargetInfo> FindPatchableElements(Stream file)
5660
//Found positions of `cook` in the binary
5761
List<long> cookiePositions = new();
5862

59-
foreach (ISection section in elf.Sections)
63+
long read = 0;
64+
65+
//Create an array twice the size of the data we are wanting to check
66+
Span<byte> arr = new byte[8];
67+
while (reader.Read(arr) == arr.Length)
6068
{
61-
// Assume a word size of 4, i would use `ProgBitsSection<T>.Alignment`
62-
// but that seems to be unrelated to the actual alignment and offset chosen for the string constants specifically (the section with all the strings is marked as 32-byte alignment[?????])
63-
// so we'll just assume 4 byte alignment since that seems universal here
64-
int wordSize = 4;
65-
ulong sectionLength;
66-
switch (section)
67-
{
68-
case ProgBitsSection<ulong> progBitsSectionUlong:
69-
file.Position = (long)progBitsSectionUlong.Offset;
70-
sectionLength = progBitsSectionUlong.Size;
71-
break;
72-
case ProgBitsSection<uint> progBitsSectionUint:
73-
file.Position = progBitsSectionUint.Offset;
74-
sectionLength = progBitsSectionUint.Size;
75-
break;
76-
default:
77-
continue;
78-
}
79-
80-
int read = 0;
81-
82-
byte[] buf = new byte[wordSize];
83-
//While we are not at the end of the file, read each word in
84-
while (read < (int)sectionLength - wordSize)
69+
long? found = null;
70+
for (int i = 0; i < 5; i++)
8571
{
86-
read += file.Read(buf);
72+
int check = BitConverter.ToInt32(arr[i..(i + 4)]);
8773

88-
int bufInt = BitConverter.ToInt32(buf);
89-
90-
//If they are equal, we found an instance of HTTP
91-
if (bufInt == httpInt)
74+
if (check == httpInt)
9275
{
93-
//Mark the position of the found instance
94-
possibleUrls.Add(reader.BaseStream.Position - wordSize);
76+
possibleUrls.Add(read + i - 4);
77+
found = read + i - 4;
78+
break;
9579
}
9680

97-
if (bufInt == cookieStartInt)
81+
// ReSharper disable once InvertIf
82+
if (check == cookieStartInt)
9883
{
99-
cookiePositions.Add(reader.BaseStream.Position - wordSize);
84+
cookiePositions.Add(read + i - 4);
85+
found = read + i - 4;
86+
break;
10087
}
10188
}
102-
}
10389

90+
//Seek 4 bytes after the position we started at, or 4 bytes after the starting index of a match
91+
reader.BaseStream.Seek(found == null ? read + 4 : found.Value + 4, SeekOrigin.Begin);
92+
93+
read += arr.Length;
94+
}
95+
10496
List<PatchTargetInfo> foundItems = new();
105-
FilterValidUrls(file, possibleUrls, reader, foundItems);
106-
FindDigestAroundCookie(file, cookiePositions, reader, foundItems);
97+
FilterValidUrls(reader, possibleUrls, foundItems);
98+
FindDigestAroundCookie(reader, cookiePositions, foundItems);
99+
100+
long end = Stopwatch.GetTimestamp();
101+
Console.WriteLine($"Detecting patchables took {(double)(end - start) / (double)Stopwatch.Frequency} seconds!");
107102
return foundItems;
108103
}
109104

110-
private static void FilterValidUrls(Stream file, List<long> foundPossibleUrlPositions, BinaryReader reader, List<PatchTargetInfo> foundItems)
105+
private static void FilterValidUrls(BinaryReader reader, List<long> foundPossibleUrlPositions, List<PatchTargetInfo> foundItems)
111106
{
112107
bool tooLong = false;
113108
foreach (long foundPosition in foundPossibleUrlPositions)
114109
{
115110
int len = 0;
116111

117-
file.Position = foundPosition;
112+
reader.BaseStream.Position = foundPosition;
118113

119114
//Find the first null byte
120115
while (reader.ReadByte() != 0)
@@ -137,13 +132,16 @@ private static void FilterValidUrls(Stream file, List<long> foundPossibleUrlPosi
137132
//Keep reading until we arent at a null byte
138133
while (reader.ReadByte() == 0) len++;
139134

140-
file.Position = foundPosition;
135+
//Remove one from length to make sure to leave a single null byte after
136+
len -= 1;
137+
138+
reader.BaseStream.Position = foundPosition;
141139

142140
//`len` at this point is the amount of bytes that are actually available to repurpose
143141
//This includes all extra null bytes except for the last one
144142

145143
byte[] match = new byte[len];
146-
if (file.Read(match) < len) continue;
144+
if (reader.Read(match) < len) continue;
147145
string str = Encoding.UTF8.GetString(match).TrimEnd('\0');
148146

149147
if (str.Contains('%')) continue; // Ignore printf strings, e.g. %s
@@ -159,11 +157,11 @@ private static void FilterValidUrls(Stream file, List<long> foundPossibleUrlPosi
159157
}
160158
}
161159

162-
private static void FindDigestAroundCookie(Stream file, List<long> foundPossibleCookiePositions, BinaryReader reader, List<PatchTargetInfo> foundItems)
160+
private static void FindDigestAroundCookie(BinaryReader reader, List<long> foundPossibleCookiePositions, List<PatchTargetInfo> foundItems)
163161
{
164162
foreach (long foundPosition in foundPossibleCookiePositions)
165163
{
166-
file.Position = foundPosition;
164+
reader.BaseStream.Position = foundPosition;
167165

168166
byte[] cookieBuf = new byte[8];
169167
//If we didnt read enough or what we read isnt "cookie\0\0"
@@ -176,7 +174,7 @@ private static void FindDigestAroundCookie(Stream file, List<long> foundPossible
176174
const int checkSize = 1000;
177175

178176
//Go back half the check size in bytes (so that `cookie` is in the middle)
179-
file.Position -= checkSize / 2;
177+
reader.BaseStream.Position -= checkSize / 2;
180178

181179
byte[] checkArr = new byte[checkSize];
182180
Span<byte> toCheck = checkArr.AsSpan().Slice(0, reader.Read(checkArr));
@@ -209,7 +207,7 @@ private static void FindDigestAroundCookie(Stream file, List<long> foundPossible
209207
foundItems.Add(new PatchTargetInfo
210208
{
211209
Length = len,
212-
Offset = file.Position - checkSize + start,
210+
Offset = reader.BaseStream.Position - checkSize + start,
213211
Data = str,
214212
Type = PatchTargetType.Digest,
215213
});

Refresher/UI/IntegratedPatchForm.cs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,19 +25,21 @@ public abstract class IntegratedPatchForm : PatchForm<Patcher>
2525
[SuppressMessage("ReSharper", "VirtualMemberCallInConstructor")]
2626
protected IntegratedPatchForm(string subtitle) : base(subtitle)
2727
{
28-
this.FormPanel = new TableLayout(new List<TableRow>
28+
List<TableRow> rows = new()
2929
{
3030
this.AddRemoteField(),
3131
AddField("Game to patch", out this._gameDropdown, forceHeight: 56),
32-
AddField("Server URL", out this.UrlField),
33-
});
32+
AddField("Server URL", out this.UrlField),
33+
};
3434

3535
if (!this.ShouldReplaceExecutable)
3636
{
37-
this.FormPanel.Rows.Add(AddField("Identifier (EBOOT.<value>.elf)", out this._outputField));
37+
rows.Add(AddField("Identifier (EBOOT.<value>.elf)", out this._outputField));
3838
this._outputField!.PlaceholderText = "refresh";
3939
}
4040

41+
this.FormPanel = new TableLayout(rows);
42+
4143
this._gameDropdown.SelectedValueChanged += this.GameChanged;
4244

4345
this.InitializePatcher();
@@ -171,7 +173,7 @@ public override void CompletePatch(object? sender, EventArgs e) {
171173
fileToUpload = this._tempFile;
172174
}
173175

174-
string destinationFile = this.ShouldReplaceExecutable ? "EBOOT.BIN" : $"EBOOT.{identifier}.BIN";
176+
string destinationFile = this.ShouldReplaceExecutable ? "EBOOT.BIN" : this.NeedsResign ? $"EBOOT.{identifier}.BIN" : $"EBOOT.{identifier}.elf";
175177
string destination = Path.Combine(this._usrDir, destinationFile);
176178

177179
// if we're replacing the executable, back it up to EBOOT.BIN.ORIG before we do so

0 commit comments

Comments
 (0)