SiniSoul
November 9th, 2010, 17:45
To do a little update to this thread;
ClientScripts
What do they do?
They are scripts. Well to be more specifically, they are activated on certain interfaces to display text. If you have ever done a search through the Jagex client, there is no string saying "Log In", or even one saying "Lobby". That is because you can consider that content dynamic, and ever so often it changes. That is why, good old Jagex saves all their strings within these scripts so that we 'modders' cannot access this information and make funny pictures like the one below.
Only the registered members can see the link. (Only the registered members can see the link.)
So in short if we could edit the cache, we could edit every single line of text that does not have any association with what the server sends.
For those of you who are slow; you could change the following:
-Skill Names
-The Stupid Message Where It Tells You To Use ` Instead Of ::
-Log In Messages
-Welcome To The RuneScape Lobby
And much more...
Now I have know how to do this on 614, courtesy of the lovely Dkk for leading me there and giving me a example on how he also did what I am about to show you. What I do know is how the script is loaded and what cache idx the scripts are within.
614 Client:
Class293.java
static final ClientScript getScript(int scriptId) {
//System.out.println("scriptId: "+scriptId);
ClientScript script = ((ClientScript) Class279_Sub46.aClass271_7327.method2436(-128, (long) scriptId));
if (script != null)
return script;
byte[] buffer = Class38.idx12.getFile(scriptId, 0);
if (buffer == null || buffer.length <= 1)
return null;
script = Class279_Sub15.loadScript(buffer);
Class279_Sub46.aClass271_7327.method2437((long) scriptId, script, (byte) 111);
return script;
}
ClientScript script = ((ClientScript) Class279_Sub46.aClass271_7327.method2436(-128, (long) scriptId));
That is just a hashmap or something reference to see if it has been loaded already.
byte[] buffer = Class38.idx12.getFile(scriptId, 0);
Read the bytes from the IDX 12.
Now this is the part where I say if you have a cache reader you could do this. No helping on that.
Class279_Sub46.aClass271_7327.method2437((long) scriptId, script, (byte) 111);
Store the script and move on.
static final ClientScript loadScript(byte[] buffer) {
anInt6903++;
ClientScript script = new ClientScript();
StreamBuffer streamBuffer = new StreamBuffer(buffer);
streamBuffer.position = streamBuffer.buffer.length - 2;
int size = streamBuffer.readUnsignedShort();
int footerOffset = streamBuffer.buffer.length - size - 12 - 2;
streamBuffer.position = footerOffset;
int scriptSize = streamBuffer.readInt();
script.intArgumentCount = streamBuffer.readUnsignedShort();
script.stringArgumentCount = streamBuffer.readUnsignedShort();
script.intStackCount = streamBuffer.readUnsignedShort();
script.stringStackCount = streamBuffer.readUnsignedShort();
int jumpCount = streamBuffer.readUnsignedByte();
if (jumpCount > 0) {
script.jumpTables = new HashTable[jumpCount];
for (int jumpIndex = 0; jumpIndex < jumpCount; jumpIndex++) {
int i_51_ = streamBuffer.readUnsignedShort();
HashTable class194 = new HashTable(Class307.method3331((byte) -125, i_51_));
script.jumpTables[jumpIndex] = class194;
while (i_51_-- > 0) {
int i_52_ = streamBuffer.readInt();
int i_53_ = streamBuffer.readInt();
class194.method1598((long) i_52_, -1, new IntegerNode(i_53_));
}
}
}
streamBuffer.position = 0;
script.name = streamBuffer.getCheckedString();
script.opcodes = new int[scriptSize];
script.intOperands = new int[scriptSize];
script.stringOperands = new String[scriptSize];
int opcount = 0;
while (streamBuffer.position < footerOffset) {
int opcode = streamBuffer.readUnsignedShort();
if (opcode == 3) {
String stringValue = streamBuffer.readString().intern();
if(stringValue.contains("RuneScape"))
stringValue = stringValue.replace("RuneScape", "RuneExtream");
if(stringValue.contains("runescape"))
stringValue = stringValue.replace("runescape", "runeextream");
if(stringValue.equals("Play Now"))
stringValue = "Troll Now";
if(stringValue.equals("Log In"))
stringValue = "Troll In";
script.stringOperands[opcount] = stringValue;
} else if (opcode >= 100 || opcode == 21 || opcode == 38 || opcode == 39)
script.intOperands[opcount] = streamBuffer.readUnsignedByte();
else
script.intOperands[opcount] = streamBuffer.readInt();
script.opcodes[opcount++] = opcode;
}
return script;
}
Here is the magic part.
int size = streamBuffer.readUnsignedShort();
int footerOffset = streamBuffer.buffer.length - size - 12 - 2;
streamBuffer.position = footerOffset;
int scriptSize = streamBuffer.readInt();
script.intArgumentCount = streamBuffer.readUnsignedShort();
script.stringArgumentCount = streamBuffer.readUnsignedShort();
script.intStackCount = streamBuffer.readUnsignedShort();
script.stringStackCount = streamBuffer.readUnsignedShort();
Is mostly initializing.
while (streamBuffer.position < footerOffset) {
int opcode = streamBuffer.readUnsignedShort();
if (opcode == 3) {
String stringValue = streamBuffer.readString().intern();
if(stringValue.contains("RuneScape"))
stringValue = stringValue.replace("RuneScape", "RuneExtream");
if(stringValue.contains("runescape"))
stringValue = stringValue.replace("runescape", "runeextream");
if(stringValue.equals("Play Now"))
stringValue = "Troll Now";
if(stringValue.equals("Log In"))
stringValue = "Troll In";
script.stringOperands[opcount] = stringValue;
} else if (opcode >= 100 || opcode == 21 || opcode == 38 || opcode == 39)
script.intOperands[opcount] = streamBuffer.readUnsignedByte();
else
script.intOperands[opcount] = streamBuffer.readInt();
script.opcodes[opcount++] = opcode;
}
This is the part of the method that we need to evaluate.
The opcode depends on the value being read. Each opcode is a unsigned short so the possible opcode range is 0 - 65535. Probally for future implementation. Considering a byte is only 0 - 255, you might run out right?
Depending on what opcode is read it stores them into to categories.
intOperands - integer/byte values
stringOperands - string values
The only function of the integer/byte operands is to reference to the string operands. (As far as I know.)
The function of those integer/byte operands might be spacing + run certain client functions like login. I will have to evaluate it more to totally understand.
Well I hope you understand client scripts a bit more, and you get to editing some of jagex's shit like I did because I hate the fact I have to look at their text all day long. Post some pictures if you do so we can get a gallery going.
Ever been confused by this packet?
if (params.length != types.length())
throw new IllegalArgumentException(
"params size should be the same as types length");
OutStream out = new OutStream(100);
out.writePacketVarShort(98);
out.writeShort(this.FrameIndex++);
out.writeString(types);
int idx = 0;
for (int i = types.length() - 1; i >= 0; i--) {
if (types.charAt(i) == 's')
out.writeString((String) params[idx]);
else
out.writeInt((Integer) params[idx]);
idx++;
}
out.writeInt(id);
out.endPacketVarShort();
player.getConnection().write(out);
Let me break this down to so we can get more scripting done.
if (params.length != types.length())
throw new IllegalArgumentException(
"params size should be the same as types length");
+
if (types.charAt(i) == 's')
out.writeString((String) params[idx]);
else
out.writeInt((Integer) params[idx]);
idx++;
Each object value you send is either a integer, or a string. This needs to be dictated so that:
Object[] = {
"hi", 1
};
The params string would be:
"is"
Simple right? Now to compare it with IviiiIsssssssss
IviiiIsssssssss would be equal to;
9 strings, 6 others
Object[] tparams3 = new Object[]{"", "", "", "", "", "", "", "", "Value", -1, 0, 7, 4, 90, 21954592};
Which as you may notice, is backwards. Don't ask why.
I believe the difference between "I" and "i" is one is a byte, one is a integer. Yes no may be?
Credits: Dkk, Me
ClientScripts
What do they do?
They are scripts. Well to be more specifically, they are activated on certain interfaces to display text. If you have ever done a search through the Jagex client, there is no string saying "Log In", or even one saying "Lobby". That is because you can consider that content dynamic, and ever so often it changes. That is why, good old Jagex saves all their strings within these scripts so that we 'modders' cannot access this information and make funny pictures like the one below.
Only the registered members can see the link. (Only the registered members can see the link.)
So in short if we could edit the cache, we could edit every single line of text that does not have any association with what the server sends.
For those of you who are slow; you could change the following:
-Skill Names
-The Stupid Message Where It Tells You To Use ` Instead Of ::
-Log In Messages
-Welcome To The RuneScape Lobby
And much more...
Now I have know how to do this on 614, courtesy of the lovely Dkk for leading me there and giving me a example on how he also did what I am about to show you. What I do know is how the script is loaded and what cache idx the scripts are within.
614 Client:
Class293.java
static final ClientScript getScript(int scriptId) {
//System.out.println("scriptId: "+scriptId);
ClientScript script = ((ClientScript) Class279_Sub46.aClass271_7327.method2436(-128, (long) scriptId));
if (script != null)
return script;
byte[] buffer = Class38.idx12.getFile(scriptId, 0);
if (buffer == null || buffer.length <= 1)
return null;
script = Class279_Sub15.loadScript(buffer);
Class279_Sub46.aClass271_7327.method2437((long) scriptId, script, (byte) 111);
return script;
}
ClientScript script = ((ClientScript) Class279_Sub46.aClass271_7327.method2436(-128, (long) scriptId));
That is just a hashmap or something reference to see if it has been loaded already.
byte[] buffer = Class38.idx12.getFile(scriptId, 0);
Read the bytes from the IDX 12.
Now this is the part where I say if you have a cache reader you could do this. No helping on that.
Class279_Sub46.aClass271_7327.method2437((long) scriptId, script, (byte) 111);
Store the script and move on.
static final ClientScript loadScript(byte[] buffer) {
anInt6903++;
ClientScript script = new ClientScript();
StreamBuffer streamBuffer = new StreamBuffer(buffer);
streamBuffer.position = streamBuffer.buffer.length - 2;
int size = streamBuffer.readUnsignedShort();
int footerOffset = streamBuffer.buffer.length - size - 12 - 2;
streamBuffer.position = footerOffset;
int scriptSize = streamBuffer.readInt();
script.intArgumentCount = streamBuffer.readUnsignedShort();
script.stringArgumentCount = streamBuffer.readUnsignedShort();
script.intStackCount = streamBuffer.readUnsignedShort();
script.stringStackCount = streamBuffer.readUnsignedShort();
int jumpCount = streamBuffer.readUnsignedByte();
if (jumpCount > 0) {
script.jumpTables = new HashTable[jumpCount];
for (int jumpIndex = 0; jumpIndex < jumpCount; jumpIndex++) {
int i_51_ = streamBuffer.readUnsignedShort();
HashTable class194 = new HashTable(Class307.method3331((byte) -125, i_51_));
script.jumpTables[jumpIndex] = class194;
while (i_51_-- > 0) {
int i_52_ = streamBuffer.readInt();
int i_53_ = streamBuffer.readInt();
class194.method1598((long) i_52_, -1, new IntegerNode(i_53_));
}
}
}
streamBuffer.position = 0;
script.name = streamBuffer.getCheckedString();
script.opcodes = new int[scriptSize];
script.intOperands = new int[scriptSize];
script.stringOperands = new String[scriptSize];
int opcount = 0;
while (streamBuffer.position < footerOffset) {
int opcode = streamBuffer.readUnsignedShort();
if (opcode == 3) {
String stringValue = streamBuffer.readString().intern();
if(stringValue.contains("RuneScape"))
stringValue = stringValue.replace("RuneScape", "RuneExtream");
if(stringValue.contains("runescape"))
stringValue = stringValue.replace("runescape", "runeextream");
if(stringValue.equals("Play Now"))
stringValue = "Troll Now";
if(stringValue.equals("Log In"))
stringValue = "Troll In";
script.stringOperands[opcount] = stringValue;
} else if (opcode >= 100 || opcode == 21 || opcode == 38 || opcode == 39)
script.intOperands[opcount] = streamBuffer.readUnsignedByte();
else
script.intOperands[opcount] = streamBuffer.readInt();
script.opcodes[opcount++] = opcode;
}
return script;
}
Here is the magic part.
int size = streamBuffer.readUnsignedShort();
int footerOffset = streamBuffer.buffer.length - size - 12 - 2;
streamBuffer.position = footerOffset;
int scriptSize = streamBuffer.readInt();
script.intArgumentCount = streamBuffer.readUnsignedShort();
script.stringArgumentCount = streamBuffer.readUnsignedShort();
script.intStackCount = streamBuffer.readUnsignedShort();
script.stringStackCount = streamBuffer.readUnsignedShort();
Is mostly initializing.
while (streamBuffer.position < footerOffset) {
int opcode = streamBuffer.readUnsignedShort();
if (opcode == 3) {
String stringValue = streamBuffer.readString().intern();
if(stringValue.contains("RuneScape"))
stringValue = stringValue.replace("RuneScape", "RuneExtream");
if(stringValue.contains("runescape"))
stringValue = stringValue.replace("runescape", "runeextream");
if(stringValue.equals("Play Now"))
stringValue = "Troll Now";
if(stringValue.equals("Log In"))
stringValue = "Troll In";
script.stringOperands[opcount] = stringValue;
} else if (opcode >= 100 || opcode == 21 || opcode == 38 || opcode == 39)
script.intOperands[opcount] = streamBuffer.readUnsignedByte();
else
script.intOperands[opcount] = streamBuffer.readInt();
script.opcodes[opcount++] = opcode;
}
This is the part of the method that we need to evaluate.
The opcode depends on the value being read. Each opcode is a unsigned short so the possible opcode range is 0 - 65535. Probally for future implementation. Considering a byte is only 0 - 255, you might run out right?
Depending on what opcode is read it stores them into to categories.
intOperands - integer/byte values
stringOperands - string values
The only function of the integer/byte operands is to reference to the string operands. (As far as I know.)
The function of those integer/byte operands might be spacing + run certain client functions like login. I will have to evaluate it more to totally understand.
Well I hope you understand client scripts a bit more, and you get to editing some of jagex's shit like I did because I hate the fact I have to look at their text all day long. Post some pictures if you do so we can get a gallery going.
Ever been confused by this packet?
if (params.length != types.length())
throw new IllegalArgumentException(
"params size should be the same as types length");
OutStream out = new OutStream(100);
out.writePacketVarShort(98);
out.writeShort(this.FrameIndex++);
out.writeString(types);
int idx = 0;
for (int i = types.length() - 1; i >= 0; i--) {
if (types.charAt(i) == 's')
out.writeString((String) params[idx]);
else
out.writeInt((Integer) params[idx]);
idx++;
}
out.writeInt(id);
out.endPacketVarShort();
player.getConnection().write(out);
Let me break this down to so we can get more scripting done.
if (params.length != types.length())
throw new IllegalArgumentException(
"params size should be the same as types length");
+
if (types.charAt(i) == 's')
out.writeString((String) params[idx]);
else
out.writeInt((Integer) params[idx]);
idx++;
Each object value you send is either a integer, or a string. This needs to be dictated so that:
Object[] = {
"hi", 1
};
The params string would be:
"is"
Simple right? Now to compare it with IviiiIsssssssss
IviiiIsssssssss would be equal to;
9 strings, 6 others
Object[] tparams3 = new Object[]{"", "", "", "", "", "", "", "", "Value", -1, 0, 7, 4, 90, 21954592};
Which as you may notice, is backwards. Don't ask why.
I believe the difference between "I" and "i" is one is a byte, one is a integer. Yes no may be?
Credits: Dkk, Me