Skip to content

Commit 44fce28

Browse files
committed
Add helpers for code replacement
1 parent 0ca66dc commit 44fce28

File tree

2 files changed

+103
-0
lines changed

2 files changed

+103
-0
lines changed
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package org.gotti.wurmunlimited.modloader.classhooks;
2+
3+
import javassist.NotFoundException;
4+
import javassist.bytecode.BadBytecode;
5+
import javassist.bytecode.CodeAttribute;
6+
import javassist.bytecode.CodeIterator;
7+
8+
/**
9+
* Replace byte code fragments with other byte code.
10+
*/
11+
public class CodeReplacer {
12+
13+
private CodeAttribute codeAttribute;
14+
15+
/**
16+
* Initialize code replace.
17+
*
18+
* @param codeAttribute
19+
*/
20+
public CodeReplacer(CodeAttribute codeAttribute) {
21+
this.codeAttribute = codeAttribute;
22+
}
23+
24+
/**
25+
* Replace the code
26+
* @param search Code to replace
27+
* @param replacement Replacement
28+
* @throws NotFoundException The code to replace was not found
29+
* @throws BadBytecode Something was wrong with the byte code
30+
*/
31+
public void replaceCode(byte[] search, byte[] replacement) throws NotFoundException, BadBytecode {
32+
int pos = findCode(search);
33+
34+
if (replacement.length <= search.length) {
35+
// Replacement is shorter or the same length as the code to replace
36+
// Replace the code and insert nops at the end
37+
writeWithNops(pos, replacement, search.length - replacement.length);
38+
} else {
39+
// Replacement is longer than the original code
40+
// Insert nops first, then write the replacement over nops and code to replace
41+
writeOverlapping(pos, replacement, replacement.length - search.length);
42+
}
43+
}
44+
45+
private void writeOverlapping(int pos, byte[] replacement, int overlapping) throws BadBytecode {
46+
CodeIterator codeIterator = codeAttribute.iterator();
47+
codeIterator.insertGap(pos, overlapping);
48+
codeIterator.write(replacement, pos);
49+
}
50+
51+
private void writeWithNops(int pos, byte[] replacement, int gap) {
52+
byte[] nops = new byte[gap];
53+
CodeIterator codeIterator = codeAttribute.iterator();
54+
codeIterator.write(replacement, pos);
55+
codeIterator.write(nops, pos + replacement.length);
56+
}
57+
58+
// Find the code fragment
59+
private int findCode(byte[] search) throws NotFoundException {
60+
byte[] code = codeAttribute.getCode();
61+
for (int i = 0, j = 0, backtrack = 0; i < code.length && j < search.length; i++) {
62+
if (code[i] == search[j]) {
63+
if (j == 0) {
64+
backtrack = i;
65+
}
66+
j++;
67+
if (j == search.length) {
68+
return backtrack;
69+
}
70+
} else if (j > 0) {
71+
i = backtrack;
72+
j = 0;
73+
}
74+
}
75+
throw new NotFoundException("code");
76+
}
77+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package org.gotti.wurmunlimited.modloader.classhooks;
2+
3+
import javassist.NotFoundException;
4+
import javassist.bytecode.LocalVariableAttribute;
5+
6+
public class LocalNameLookup {
7+
8+
private LocalVariableAttribute attr;
9+
10+
public LocalNameLookup(LocalVariableAttribute attribute) {
11+
this.attr = attribute;
12+
}
13+
14+
public int get(String name) throws NotFoundException {
15+
if (name == null) {
16+
throw new NotFoundException(name);
17+
}
18+
for (int i = 0; i < attr.tableLength(); i++) {
19+
if (name.equals(attr.variableName(i))) {
20+
return attr.index(i);
21+
}
22+
}
23+
throw new NotFoundException(name);
24+
}
25+
26+
}

0 commit comments

Comments
 (0)