
リバースエンジニアリングされたEasy Anti-Cheatカーネルドライババイパス。メモリ割り当てを傍受して違反パケットを抑制し、レポート復号ルーチンと分析ノートを備える。
私のコードではありません。保存用です https://www.unknowncheats.me/forum/anti-cheat-bypass/503052-easy-anti-cheat-kernel-packet-fucker.html
これは Easy Anti-Cheat Kernel Packet Fucker(略して EACKPFucker)です。 これは何か?基本的に、カーネルモードドライバー経由のパケットが彼らに送信されなくなるため、あなたの pasta pasta 2023 kdmapper FUD バイパスを何の問題もなく使用できます。
わかったよ、驚かされたよ。これは一体どうやって動くんだ? 単に1つのアドレスを変更するだけです。さて、EAC が実際にどのように動作するのかを深く掘り下げていきましょう。
最初から言うと、Easy Anti-Cheat があなたを BAN するには、実際にあなたのデータを取得する必要があります。これらのパケットは彼らの Hydra チャネルを介して送信され、暗号学的に安全です。このバイパスに必要な知識はこれだけです。これ以上詳しくは説明しません。
彼らのカーネルドライバー内部でこれがどのように動作するか、ランダムな違反を例に見てみましょう:

これ、脆弱に見えませんか?少なくとも私にはそう見えます。
最初の関数を見てみましょう:kalloc_rt
うーん、なるほど。では alloc_pool_with_tag に飛び込んでみましょう
動的に ExAllocatePoolWithTag をインポートしています。ふむむ…もし誰かがその qword を自分で改造した malloc 関数に書き換えたらどうなるだろう…(ええ、動きます -- しかも書き込み可能なセクションを変更しているので、EAC はまったく気づきません)
よし、これでメモリ割り当てを制御できるようになりました。クール!これで何ができるんだ?
聞いてくれて嬉しいよ!こういうことだ:カーネルモードからのパケットはすべて 33096i64 のサイズです…そして先ほど見たように、メモリが割り当てられなければ、EAC はただ…違反を無視します。
よし、誰かが単純に…こうしたとしよう:



---------------------------------------------------------------------------------------------------------------------------------------```C++ // report encryption looks like this (some parts may vary for each report, i believe they use key1, key2, key3 to use only 1 function for decryption) static report_t* encrypt(uint8_t* data, uint64_t size) {
report_t* packet = (report_t*)malloc(sizeof(report_t));
if (!packet) return nullptr;
uint32_t seed = 0x80BE5ED5 * ((uint64_t)&data >> 2);
memset(&packet->key1, 0, 0x8200);
packet->raw_size = 0;
packet->key1 = 0x66259F86; // gives key4?
packet->key2 = 0x21EBA81; // gives key5?
packet->key3 = 0xACE987AF; // gives key6?
packet->key4 = 0x50BFC583; // gives seed
packet->key5 = 0x3C61A927; // gives dynamic_key (from end)
packet->key6 = 0x70881859; // gives actual payload size
uint8_t* raw_data = packet->raw;
uint64_t raw_size = 24;
uint8_t* payload_data = packet->payload;
uint64_t payload_size = 0;
uint32_t dynamic_key = seed ^ 0x6957FDB6;
while (payload_size < size && payload_size < 0x8000) {
uint32_t a = (dynamic_key << 0xD) ^ dynamic_key;
uint32_t b = (a >> 0x11) ^ a;
uint32_t c = (b << 0x5) ^ b;
uint32_t d = _rotr(c, 2);
uint8_t shift = 8 * (payload_size & 3);
payload_data[payload_size] = data[payload_size] ^ (d >> shift);
dynamic_key = data[payload_size] ^ d;
payload_size++;
raw_size++;
}
uint64_t aligned_size = (raw_size + 0xFF) & ~0xFF; // align up by 0x100
while (raw_size < aligned_size) {
dynamic_key *= 0x80BE5ED5;
raw_data[raw_size++] = dynamic_key;
}
packet->key4 ^= seed;
packet->key5 ^= dynamic_key;
packet->key6 ^= payload_size;
packet->raw_size = raw_size;
return packet;
}
// thus my decryption looks like this static void decrypt(report_t* packet) {
uint32_t seed = packet->key4 ^ 0x50BFC583;
uint32_t dynamic_key = seed ^ 0x6957FDB6;
//uint32_t dynamic_key = packet->key5 ^ 0x3C61A927;
uint8_t* payload_data = packet->payload;
uint32_t payload_size = packet->key6 ^ 0x70881859;
for (uint32_t i = 0; i < payload_size; i++) {
uint32_t a = (dynamic_key << 0xD) ^ dynamic_key;
uint32_t b = (a >> 0x11) ^ a;
uint32_t c = (b << 0x5) ^ b;
uint32_t d = _rotr(c, 2);
uint8_t shift = 8 * (i & 3);
payload_data[i] ^= (d >> shift);
dynamic_key = payload_data[i] ^ d;
}
}
after dumping some reports and decrypting: