Commit 68969669 authored by Him188's avatar Him188

Change into Kotlin

parent 888faaa6
import kotlin.ranges.IntRange;
import net.mamoe.mirai.network.protocol.tim.TIMProtocol;
import net.mamoe.mirai.network.protocol.tim.packet.ClientPacketKt;
import net.mamoe.mirai.utils.UtilsKt;
import java.awt.*;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiConsumer;
@file:Suppress("ObjectPropertyName", "unused", "NonAsciiCharacters", "MayBeConstant")
import net.mamoe.mirai.network.protocol.tim.TIMProtocol
import net.mamoe.mirai.network.protocol.tim.packet.toUHexString
import net.mamoe.mirai.utils.toUHexString
import java.awt.Toolkit
import java.awt.datatransfer.DataFlavor
import java.lang.reflect.Field
import java.util.*
import kotlin.math.max
/**
* Hex 比较器, 并着色已知常量
*
* This could be used to check packet encoding..
* but better to run under UNIX
*
* @author NaturalHG
* @author Him188moe
*/
public class HexComparator {
object HexComparator {
/**
* a string result
*/
private val RED = "\u001b[31m"
private static final String RED = "\033[31m";
private val GREEN = "\u001b[33m"
private static final String GREEN = "\033[33m";
private val UNKNOWN = "\u001b[30m"
private static final String UNKNOWN = "\033[30m";
private val BLUE = "\u001b[34m"
private static final String BLUE = "\033[34m";
public static final List<HexReader> consts = new LinkedList<>() {{
add(new HexReader("90 5E 39 DF 00 02 76 E4 B8 DD 00"));
}};
private val clipboardString: String?
get() {
val trans = Toolkit.getDefaultToolkit().systemClipboard.getContents(null)
if (trans.isDataFlavorSupported(DataFlavor.stringFlavor)) {
try {
return trans.getTransferData(DataFlavor.stringFlavor) as String
} catch (e: Exception) {
e.printStackTrace()
}
private static class ConstMatcher {
private static final List<Field> CONST_FIELDS = new LinkedList<>() {{
List.of(TIMProtocol.class).forEach(aClass -> Arrays.stream(aClass.getDeclaredFields()).peek(this::add).forEach(Field::trySetAccessible));
List.of(TestConsts.class).forEach(aClass -> Arrays.stream(aClass.getDeclaredFields()).peek(this::add).forEach(Field::trySetAccessible));
}};
}
@SuppressWarnings({"unused", "NonAsciiCharacters"})
private static class TestConsts {
private static final String NIU_BI = UtilsKt.toUHexString("牛逼".getBytes(), " ");
private static final String _1994701021 = ClientPacketKt.toUHexString(1994701021, " ");
private static final String _1040400290 = ClientPacketKt.toUHexString(1040400290, " ");
private static final String _580266363 = ClientPacketKt.toUHexString(580266363, " ");
return null
}
private static final String _1040400290_ = "3E 03 3F A2";
private static final String _1994701021_ = "76 E4 B8 DD";
private static final String _jiahua_ = "B1 89 BE 09";
private static final String _Him188moe_ = UtilsKt.toUHexString("Him188moe".getBytes(), " ");
private static final String 发图片 = UtilsKt.toUHexString("发图片".getBytes(), " ");
private static final String = UtilsKt.toUHexString("发图片".getBytes(), " ");
class ConstMatcher constructor(hex: String) {
private static final String SINGLE_PLAIN_MESSAGE_HEAD = "00 00 01 00 09 01";
private val matches = LinkedList<Match>()
private static final String MESSAGE_TAIL_10404 = "0E 00 07 01 00 04 00 00 00 09 19 00 18 01 00 15 AA 02 12 9A 01 0F 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00".replace(" ", " ");
//private static final String MESSAGE_TAIL2_10404 ="".replace(" ", " ");
object TestConsts {
val NIU_BI = "牛逼".toByteArray().toUHexString()
val _1994701021 = 1994701021.toUHexString(" ")
val _1040400290 = 1040400290.toUHexString(" ")
val _580266363 = 580266363.toUHexString(" ")
}
val _1040400290_ = "3E 03 3F A2"
val _1994701021_ = "76 E4 B8 DD"
val _jiahua_ = "B1 89 BE 09"
val _Him188moe_ = "Him188moe".toByteArray().toUHexString()
val 发图片 = "发图片".toByteArray().toUHexString()
val 群 = "群".toByteArray().toUHexString()
val SINGLE_PLAIN_MESSAGE_HEAD = "00 00 01 00 09 01"
private final List<Match> matches = new LinkedList<>();
val MESSAGE_TAIL_10404 = "0E 00 07 01 00 04 00 00 00 09 19 00 18 01 00 15 AA 02 12 9A 01 0F 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00"
.replace(" ", " ")
}
private ConstMatcher(String hex) {
CONST_FIELDS.forEach(field -> {
for (IntRange match : match(hex, field)) {
matches.add(new Match(match, field.getName()));
init {
CONST_FIELDS.forEach { field ->
for (match in match(hex, field)) {
matches.add(Match(match, field.name))
}
}
});
}
private String getMatchedConstName(int hexNumber) {
for (Match match : this.matches) {
fun getMatchedConstName(hexNumber: Int): String? {
for (match in this.matches) {
if (match.range.contains(hexNumber)) {
return match.constName;
return match.constName
}
}
return null;
return null
}
private static List<IntRange> match(String hex, Field field) {
final String constValue;
try {
constValue = ((String) field.get(null)).trim();
if (constValue.length() / 3 <= 3) {//Minimum numbers of const hex bytes
return new LinkedList<>();
private class Match internal constructor(val range: IntRange, val constName: String)
companion object {
private val CONST_FIELDS: List<Field> = listOf(
TestConsts::class.java,
TIMProtocol::class.java
).map { it.declaredFields }.flatMap { fields ->
fields.map { field ->
field.trySetAccessible()
field
}
}
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (ClassCastException ignored) {
return new LinkedList<>();
}
return new LinkedList<>() {{
int index = -1;
while ((index = hex.indexOf(constValue, index + 1)) != -1) {
add(new IntRange(index / 3, (index + constValue.length()) / 3));
private fun match(hex: String, field: Field): List<IntRange> {
val constValue: String
try {
constValue = (field.get(null) as String).trim { it <= ' ' }
if (constValue.length / 3 <= 3) {//Minimum numbers of const hex bytes
return LinkedList()
}
}};
} catch (e: IllegalAccessException) {
throw RuntimeException(e)
} catch (ignored: ClassCastException) {
return LinkedList()
}
private static class Match {
private IntRange range;
private String constName;
return object : LinkedList<IntRange>() {
init {
var index = -1
index = hex.indexOf(constValue, index + 1)
while (index != -1) {
add(IntRange(index / 3, (index + constValue.length) / 3))
Match(IntRange range,String constName){
this.range = range;
this.constName = constName;
index = hex.indexOf(constValue, index + 1)
}
}
}
}
}
private static void buildConstNameChain(int length, ConstMatcher constMatcher, StringBuilder constNameBuilder) {
private fun buildConstNameChain(length: Int, constMatcher: ConstMatcher, constNameBuilder: StringBuilder) {
//System.out.println(constMatcher.matches);
for (int i = 0; i < length; i++) {
constNameBuilder.append(" ");
String match = constMatcher.getMatchedConstName(i / 4);
var i = 0
while (i < length) {
constNameBuilder.append(" ")
val match = constMatcher.getMatchedConstName(i / 4)
if (match != null) {
int appendedNameLength = match.length();
constNameBuilder.append(match);
while (match.equals(constMatcher.getMatchedConstName(i++ / 4))) {
var appendedNameLength = match.length
constNameBuilder.append(match)
while (match == constMatcher.getMatchedConstName(i++ / 4)) {
if (appendedNameLength-- < 0) {
constNameBuilder.append(" ");
constNameBuilder.append(" ")
}
}
constNameBuilder.append(" ".repeat(match.length() % 4));
constNameBuilder.append(" ".repeat(match.length % 4))
}
i++
}
}
private static String compare(String hex1s, String hex2s) {
StringBuilder builder = new StringBuilder();
fun compare(hex1s: String, hex2s: String): String {
val builder = StringBuilder()
String[] hex1 = hex1s.trim().replace("\n", "").split(" ");
String[] hex2 = hex2s.trim().replace("\n", "").split(" ");
ConstMatcher constMatcher1 = new ConstMatcher(hex1s);
ConstMatcher constMatcher2 = new ConstMatcher(hex2s);
val hex1 = hex1s.trim { it <= ' ' }.replace("\n", "").split(" ".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
val hex2 = hex2s.trim { it <= ' ' }.replace("\n", "").split(" ".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
val constMatcher1 = ConstMatcher(hex1s)
val constMatcher2 = ConstMatcher(hex2s)
if (hex1.length == hex2.length) {
builder.append(GREEN).append("长度一致:").append(hex1.length);
if (hex1.size == hex2.size) {
builder.append(GREEN).append("长度一致:").append(hex1.size)
} else {
builder.append(RED).append("长度不一致").append(hex1.length).append("/").append(hex2.length);
builder.append(RED).append("长度不一致").append(hex1.size).append("/").append(hex2.size)
}
StringBuilder numberLine = new StringBuilder();
StringBuilder hex1ConstName = new StringBuilder();
StringBuilder hex1b = new StringBuilder();
StringBuilder hex2b = new StringBuilder();
StringBuilder hex2ConstName = new StringBuilder();
int dif = 0;
val numberLine = StringBuilder()
val hex1ConstName = StringBuilder()
val hex1b = StringBuilder()
val hex2b = StringBuilder()
val hex2ConstName = StringBuilder()
var dif = 0
int length = Math.max(hex1.length, hex2.length) * 4;
buildConstNameChain(length, constMatcher1, hex1ConstName);
buildConstNameChain(length, constMatcher2, hex2ConstName);
val length = max(hex1.size, hex2.size) * 4
buildConstNameChain(length, constMatcher1, hex1ConstName)
buildConstNameChain(length, constMatcher2, hex2ConstName)
for (int i = 0; i < Math.max(hex1.length, hex2.length); ++i) {
String h1 = null;
String h2 = null;
boolean isDif = false;
if (hex1.length <= i) {
h1 = RED + "__";
isDif = true;
for (i in 0 until max(hex1.size, hex2.size)) {
var h1: String? = null
var h2: String? = null
var isDif = false
if (hex1.size <= i) {
h1 = RED + "__"
isDif = true
} else {
String matchedConstName = constMatcher1.getMatchedConstName(i);
val matchedConstName = constMatcher1.getMatchedConstName(i)
if (matchedConstName != null) {
h1 = BLUE + hex1[i];
h1 = BLUE + hex1[i]
}
}
if (hex2.length <= i) {
h2 = RED + "__";
isDif = true;
if (hex2.size <= i) {
h2 = RED + "__"
isDif = true
} else {
String matchedConstName = constMatcher2.getMatchedConstName(i);
val matchedConstName = constMatcher2.getMatchedConstName(i)
if (matchedConstName != null) {
h2 = BLUE + hex2[i];
h2 = BLUE + hex2[i]
}
}
if (h1 == null && h2 == null) {
h1 = hex1[i];
h2 = hex2[i];
if (h1.equals(h2)) {
h1 = GREEN + h1;
h2 = GREEN + h2;
h1 = hex1[i]
h2 = hex2[i]
if (h1 == h2) {
h1 = GREEN + h1
h2 = GREEN + h2
} else {
h1 = RED + h1;
h2 = RED + h2;
isDif = true;
h1 = RED + h1
h2 = RED + h2
isDif = true
}
} else {
if (h1 == null) {
h1 = RED + hex1[i];
h1 = RED + hex1[i]
}
if (h2 == null) {
h2 = RED + hex2[i];
h2 = RED + hex2[i]
}
}
numberLine.append(UNKNOWN).append(getFixedNumber(i)).append(" ");
hex1b.append(" ").append(h1).append(" ");
hex2b.append(" ").append(h2).append(" ");
numberLine.append(UNKNOWN).append(getFixedNumber(i)).append(" ")
hex1b.append(" ").append(h1).append(" ")
hex2b.append(" ").append(h2).append(" ")
if (isDif) {
++dif;
++dif
}
//doConstReplacement(hex1b);
//doConstReplacement(hex2b);
}
return (builder.append(" ").append(dif).append(" 个不同").append("\n")
return builder.append(" ").append(dif).append(" 个不同").append("\n")
.append(numberLine).append("\n")
.append(hex1ConstName).append("\n")
.append(hex1b).append("\n")
.append(hex2b).append("\n")
.append(hex2ConstName).append("\n")
)
.toString();
.toString()
}
private static void doConstReplacement(StringBuilder builder) {
String mirror = builder.toString();
HexReader hexs = new HexReader(mirror);
for (AtomicInteger i = new AtomicInteger(0); i.get() < builder.length(); i.addAndGet(1)) {
hexs.setTo(i.get());
consts.forEach(a -> {
hexs.setTo(i.get());
List<Integer> posToPlaceColor = new LinkedList<>();
AtomicBoolean is = new AtomicBoolean(false);
a.readFully((c, d) -> {
if (c.equals(hexs.readHex())) {
posToPlaceColor.add(d);
} else {
is.set(false);
}
});
if (is.get()) {
AtomicInteger adder = new AtomicInteger();
posToPlaceColor.forEach(e -> {
builder.insert(e + adder.getAndAdd(BLUE.length()), BLUE);
});
}
});
}
}
private static String getFixedNumber(int number) {
private fun getFixedNumber(number: Int): String {
if (number < 10) {
return "00" + number;
}
if (number < 100) {
return "0" + number;
}
return String.valueOf(number);
}
private static String getClipboardString() {
Transferable trans = Toolkit.getDefaultToolkit().getSystemClipboard().getContents(null);
if (trans.isDataFlavorSupported(DataFlavor.stringFlavor)) {
try {
return (String) trans.getTransferData(DataFlavor.stringFlavor);
} catch (Exception e) {
e.printStackTrace();
return "00$number"
}
return if (number < 100) {
"0$number"
} else number.toString()
}
return null;
}
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
fun main() {
val scanner = Scanner(System.`in`)
while (true) {
System.out.println("Hex1: ");
var hex1 = scanner.nextLine();
System.out.println("Hex2: ");
var hex2 = scanner.nextLine();
System.out.println("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
System.out.println(HexComparator.compare(hex1, hex2));
System.out.println();
}
/*
println("Hex1: ")
val hex1 = scanner.nextLine()
println("Hex2: ")
val hex2 = scanner.nextLine()
println("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n")
println(HexComparator.compare(hex1, hex2))
println()
}
/*
System.out.println(HexComparator.compare(
//mirai
......@@ -301,6 +271,7 @@ public class HexComparator {
//e
"2A 22 96 29 7B 00 3F 00 01 01 00 00 00 00 00 00 00 4D 53 47 00 00 00 00 00 5D 6B 8E 1A FE 39 0B FC Protocol.messageConst1 00 00 01 00 0A 01 00 07 6D 65 73 73 61 67 65"
));
*/
/*
......@@ -310,64 +281,4 @@ public class HexComparator {
//mirai
"6F 0B DF 92 00 02 76 E4 B8 DD 00 00 04 53 00 00 00 01 00 00 15 85 00 00 01 55 35 05 8E C9 BA 16 D0 01 63 5B 59 4B 59 52 31 01 B9 00 00 00 00 00 00 00 00 00 00 00 00 00 E9 E9 E9 E9 00 00 00 00 00 00 00 00 00 10 15 74 C4 89 85 7A 19 F5 5E A9 C9 A3 5E 8A 5A 9B AA BB CC DD EE FF AA BB CC\n\n\n"
));*/
}
}
class HexReader {
private String s;
private int pos = 0;
private int lastHaxPos = 0;
public HexReader(String s) {
this.s = s;
}
public String readHex() {
boolean isStr = false;
String next = "";
for (; pos < s.length() - 2; ++pos) {
char s1 = ' ';
if (pos != 0) {
s1 = this.s.charAt(0);
}
char s2 = this.s.charAt(pos + 1);
char s3 = this.s.charAt(pos + 2);
char s4 = ' ';
if (this.s.length() != (this.pos + 3)) {
s4 = this.s.charAt(pos + 3);
}
if (
Character.isSpaceChar(s1) && Character.isSpaceChar(s4)
&&
(Character.isDigit(s2) || Character.isAlphabetic(s2))
&&
(Character.isDigit(s3) || Character.isAlphabetic(s3))
) {
this.pos += 2;
this.lastHaxPos = this.pos + 1;
return String.valueOf(s2) + s3;
}
}
return "";
}
public void readFully(BiConsumer<String, Integer> processor) {
this.reset();
String nextHax = this.readHex();
while (!nextHax.equals(" ")) {
processor.accept(nextHax, this.lastHaxPos);
nextHax = this.readHex();
}
}
public void setTo(int pos) {
this.pos = pos;
}
public void reset() {
this.pos = 0;
}
}
\ No newline at end of file
......@@ -10,7 +10,7 @@ import net.mamoe.mirai.utils.*
import java.io.DataInputStream
/**
* 模拟登录并抓取到 session key
* 抓包分析器
*
* @author Him188moe
*/
......@@ -74,12 +74,18 @@ object Main {
/**
* 从 TIM 内存中读取.
* 可从 TIM 内存中读取
*
* 方法:
* 在 Common.dll 中搜索
* 1. x32dbg 附加 TIM
* 2. `符号` 中找到 common.dll
* 3. 搜索函数 `oi_symmetry_encrypt2` (TEA 加密函数)
* 4. 双击跳转
* 5. 断点并在TIM发送消息以触发
* 6. 运行到 `mov eax,dword ptr ss:[ebp+10]`
* 7. 从 eax 开始的 16个 bytes 便是 `sessionKey`
*/
const val sessionKey: String = "70 BD 1E 12 20 C1 25 12 A0 F8 4F 0D C0 A0 97 0E"
val sessionKey: ByteArray = "48 C0 11 42 2D FD 8F 36 6E BA BF FD D3 AA B7 AE".hexToBytes()
fun dataReceived(data: ByteArray) {
packetReceived(ServerPacket.ofByteArray(data))
......@@ -88,7 +94,6 @@ object Main {
fun packetReceived(packet: ServerPacket) {
when (packet) {
is ServerEventPacket.Raw.Encrypted -> {
val sessionKey = "8B 45 10 0F 10 00 66 0F 38 00 05 20 39 18 64 0F".hexToBytes()
println("! ServerEventPacket.Raw.Encrypted")
packetReceived(packet.decrypt(sessionKey))
println("! decrypt succeed")
......@@ -112,21 +117,12 @@ object Main {
//it.readShort()
//println(it.readUInt())
println(it.readNBytes(TIMProtocol.fixVer2.hexToBytes().size + 1 + 5 - 3 + 1).toUHexString())
it.readAllBytes().let {
println("解密")
println(it.size)
println(it.toUHexString())
println(it.decryptBy(sessionKey).toUHexString())
val messageData = it.readAllBytes().decryptBy(sessionKey)
}
}
}
}
}
}
private fun ByteArray.decryptBy(key: ByteArray): ByteArray = TEA.decrypt(this, key)
private fun ByteArray.decryptBy(key: String): ByteArray = TEA.decrypt(this, key)
private fun DataInputStream.skipHex(uHex: String) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment