feat: 为反检测做准备

This commit is contained in:
手瓜一十雪
2026-02-13 14:28:25 +08:00
parent d622178b25
commit 62c9246368
8 changed files with 114 additions and 32 deletions

View File

@@ -33,6 +33,7 @@ import { NodeIKernelMsgListener, NodeIKernelProfileListener } from '@/napcat-cor
import { proxiedListenerOf } from '@/napcat-core/helper/proxy-handler'; import { proxiedListenerOf } from '@/napcat-core/helper/proxy-handler';
import { NTQQPacketApi } from './apis/packet'; import { NTQQPacketApi } from './apis/packet';
import { NativePacketHandler } from './packet/handler/client'; import { NativePacketHandler } from './packet/handler/client';
import { Napi2NativeLoader } from './packet/handler/napi2nativeLoader';
import { container, ReceiverServiceRegistry } from './packet/handler/serviceRegister'; import { container, ReceiverServiceRegistry } from './packet/handler/serviceRegister';
import { appEvent } from './packet/handler/eventList'; import { appEvent } from './packet/handler/eventList';
import { TypedEventEmitter } from './packet/handler/typeEvent'; import { TypedEventEmitter } from './packet/handler/typeEvent';
@@ -314,6 +315,7 @@ export interface InstanceContext {
readonly basicInfoWrapper: QQBasicInfoWrapper; readonly basicInfoWrapper: QQBasicInfoWrapper;
readonly pathWrapper: NapCatPathWrapper; readonly pathWrapper: NapCatPathWrapper;
readonly packetHandler: NativePacketHandler; readonly packetHandler: NativePacketHandler;
readonly napi2nativeLoader: Napi2NativeLoader;
} }
export interface StableNTApiWrapper { export interface StableNTApiWrapper {

View File

@@ -1,11 +1,8 @@
import path, { dirname } from 'path';
import { fileURLToPath } from 'url';
import fs from 'fs';
import { constants } from 'node:os';
import { LogStack } from '@/napcat-core/packet/context/clientContext'; import { LogStack } from '@/napcat-core/packet/context/clientContext';
import { NapCoreContext } from '@/napcat-core/packet/context/napCoreContext'; import { NapCoreContext } from '@/napcat-core/packet/context/napCoreContext';
import { PacketLogger } from '@/napcat-core/packet/context/loggerContext'; import { PacketLogger } from '@/napcat-core/packet/context/loggerContext';
import { OidbPacket, PacketBuf } from '@/napcat-core/packet/transformer/base'; import { OidbPacket, PacketBuf } from '@/napcat-core/packet/transformer/base';
import { Napi2NativeLoader } from '@/napcat-core/packet/handler/napi2nativeLoader';
export interface RecvPacket { export interface RecvPacket {
type: string, // 仅recv type: string, // 仅recv
data: RecvPacketData; data: RecvPacketData;
@@ -17,50 +14,38 @@ export interface RecvPacketData {
data: Buffer; data: Buffer;
} }
// 0 send 1 recv
export interface NativePacketExportType {
initHook?: (send: string, recv: string) => boolean;
}
export class NativePacketClient { export class NativePacketClient {
protected readonly napcore: NapCoreContext; protected readonly napcore: NapCoreContext;
protected readonly logger: PacketLogger; protected readonly logger: PacketLogger;
protected readonly cb = new Map<string, (json: RecvPacketData) => Promise<any> | any>(); // hash-type callback protected readonly cb = new Map<string, (json: RecvPacketData) => Promise<any> | any>(); // hash-type callback
protected readonly napi2nativeLoader: Napi2NativeLoader;
logStack: LogStack; logStack: LogStack;
available: boolean = false; available: boolean = false;
private readonly supportedPlatforms = ['win32.x64', 'linux.x64', 'linux.arm64', 'darwin.x64', 'darwin.arm64'];
private readonly MoeHooExport: { exports: NativePacketExportType; } = { exports: {} };
constructor (napCore: NapCoreContext, logger: PacketLogger, logStack: LogStack) { constructor (napCore: NapCoreContext, logger: PacketLogger, logStack: LogStack, napi2nativeLoader: Napi2NativeLoader) {
this.napcore = napCore; this.napcore = napCore;
this.logger = logger; this.logger = logger;
this.logStack = logStack; this.logStack = logStack;
this.napi2nativeLoader = napi2nativeLoader;
} }
check (): boolean { check (): boolean {
const platform = process.platform + '.' + process.arch; if (!this.napi2nativeLoader.loaded) {
if (!this.supportedPlatforms.includes(platform)) { this.logStack.pushLogWarn('NativePacketClient: Napi2NativeLoader 未成功加载');
this.logStack.pushLogWarn(`NativePacketClient: 不支持的平台: ${platform}`);
return false;
}
const moehoo_path = path.join(dirname(fileURLToPath(import.meta.url)), './native/napi2native/napi2native.' + platform + '.node');
if (!fs.existsSync(moehoo_path)) {
this.logStack.pushLogWarn(`NativePacketClient: 缺失运行时文件: ${moehoo_path}`);
return false; return false;
} }
return true; return true;
} }
async init (_pid: number, recv: string, send: string): Promise<void> { async init (_pid: number, recv: string, send: string): Promise<void> {
const platform = process.platform + '.' + process.arch;
const isNewQQ = this.napcore.basicInfo.requireMinNTQQBuild('40824'); const isNewQQ = this.napcore.basicInfo.requireMinNTQQBuild('40824');
if (isNewQQ) { if (isNewQQ) {
const moehoo_path = path.join(dirname(fileURLToPath(import.meta.url)), './native/napi2native/napi2native.' + platform + '.node'); const success = this.napi2nativeLoader.initHook(send, recv);
process.dlopen(this.MoeHooExport, moehoo_path, constants.dlopen.RTLD_LAZY); if (success) {
this.MoeHooExport?.exports.initHook?.(send, recv);
this.available = true; this.available = true;
} }
} }
}
async sendPacket ( async sendPacket (
cmd: string, cmd: string,

View File

@@ -2,6 +2,7 @@ import { NativePacketClient } from '@/napcat-core/packet/client/nativeClient';
import { OidbPacket } from '@/napcat-core/packet/transformer/base'; import { OidbPacket } from '@/napcat-core/packet/transformer/base';
import { PacketLogger } from '@/napcat-core/packet/context/loggerContext'; import { PacketLogger } from '@/napcat-core/packet/context/loggerContext';
import { NapCoreContext } from '@/napcat-core/packet/context/napCoreContext'; import { NapCoreContext } from '@/napcat-core/packet/context/napCoreContext';
import { Napi2NativeLoader } from '@/napcat-core/packet/handler/napi2nativeLoader';
export class LogStack { export class LogStack {
private stack: string[] = []; private stack: string[] = [];
@@ -43,12 +44,14 @@ export class PacketClientContext {
private readonly napCore: NapCoreContext; private readonly napCore: NapCoreContext;
private readonly logger: PacketLogger; private readonly logger: PacketLogger;
private readonly logStack: LogStack; private readonly logStack: LogStack;
private readonly napi2nativeLoader: Napi2NativeLoader;
private readonly _client: NativePacketClient; private readonly _client: NativePacketClient;
constructor (napCore: NapCoreContext, logger: PacketLogger) { constructor (napCore: NapCoreContext, logger: PacketLogger, napi2nativeLoader: Napi2NativeLoader) {
this.napCore = napCore; this.napCore = napCore;
this.logger = logger; this.logger = logger;
this.logStack = new LogStack(logger); this.logStack = new LogStack(logger);
this.napi2nativeLoader = napi2nativeLoader;
this._client = this.newClient(); this._client = this.newClient();
} }
@@ -71,7 +74,7 @@ export class PacketClientContext {
private newClient (): NativePacketClient { private newClient (): NativePacketClient {
this.logger.info('使用 NativePacketClient 作为后端'); this.logger.info('使用 NativePacketClient 作为后端');
const client = new NativePacketClient(this.napCore, this.logger, this.logStack); const client = new NativePacketClient(this.napCore, this.logger, this.logStack, this.napi2nativeLoader);
if (!client.check()) { if (!client.check()) {
throw new Error('[Core] [Packet] NativePacketClient 不可用NapCat.Packet将不会加载'); throw new Error('[Core] [Packet] NativePacketClient 不可用NapCat.Packet将不会加载');
} }

View File

@@ -34,5 +34,9 @@ export class NapCoreContext {
return this.core.configLoader.configData; return this.core.configLoader.configData;
} }
get napi2nativeLoader () {
return this.core.context.napi2nativeLoader;
}
sendSsoCmdReqByContend = (cmd: string, data: Buffer) => this.core.context.session.getMsgService().sendSsoCmdReqByContend(cmd, data); sendSsoCmdReqByContend = (cmd: string, data: Buffer) => this.core.context.session.getMsgService().sendSsoCmdReqByContend(cmd, data);
} }

View File

@@ -18,7 +18,7 @@ export class PacketContext {
this.msgConverter = new PacketMsgConverter(); this.msgConverter = new PacketMsgConverter();
this.napcore = new NapCoreContext(core); this.napcore = new NapCoreContext(core);
this.logger = new PacketLogger(this.napcore); this.logger = new PacketLogger(this.napcore);
this.client = new PacketClientContext(this.napcore, this.logger); this.client = new PacketClientContext(this.napcore, this.logger, this.napcore.napi2nativeLoader);
this.highway = new PacketHighwayContext(this.napcore, this.logger, this.client); this.highway = new PacketHighwayContext(this.napcore, this.logger, this.client);
this.operation = new PacketOperationContext(this); this.operation = new PacketOperationContext(this);
} }

View File

@@ -0,0 +1,79 @@
import path, { dirname } from 'path';
import { fileURLToPath } from 'url';
import fs from 'fs';
import { constants } from 'node:os';
import { LogWrapper } from '../../helper/log';
export interface Napi2NativeExportType {
initHook?: (send: string, recv: string) => boolean;
}
export class Napi2NativeLoader {
private readonly supportedPlatforms = ['win32.x64', 'linux.x64', 'linux.arm64', 'darwin.x64', 'darwin.arm64'];
private readonly exports: { exports: Napi2NativeExportType; } = { exports: {} };
protected readonly logger: LogWrapper;
private _loaded: boolean = false;
constructor ({ logger }: { logger: LogWrapper; }) {
this.logger = logger;
this.load();
}
private load (): void {
const platform = process.platform + '.' + process.arch;
if (!this.supportedPlatforms.includes(platform)) {
this.logger.logWarn(`Napi2NativeLoader: 不支持的平台: ${platform}`);
this._loaded = false;
return;
}
const nativeModulePath = path.join(
dirname(fileURLToPath(import.meta.url)),
'./native/napi2native/napi2native.' + platform + '.node'
);
if (!fs.existsSync(nativeModulePath)) {
this.logger.logWarn(`Napi2NativeLoader: 缺失运行时文件: ${nativeModulePath}`);
this._loaded = false;
return;
}
try {
process.dlopen(this.exports, nativeModulePath, constants.dlopen.RTLD_LAZY);
this._loaded = true;
this.logger.log('[Napi2NativeLoader] 加载成功');
} catch (error) {
this.logger.logError('Napi2NativeLoader 加载出错:', error);
this._loaded = false;
}
}
get loaded (): boolean {
return this._loaded;
}
get nativeExports (): Napi2NativeExportType {
return this.exports.exports;
}
/**
* 初始化 Hook
* @param send send 偏移地址
* @param recv recv 偏移地址
* @returns 是否初始化成功
*/
initHook (send: string, recv: string): boolean {
if (!this._loaded) {
this.logger.logWarn('Napi2NativeLoader 未成功加载,无法初始化 Hook');
return false;
}
try {
return this.nativeExports.initHook?.(send, recv) ?? false;
} catch (error) {
this.logger.logError('Napi2NativeLoader initHook 出错:', error);
return false;
}
}
}

View File

@@ -2,6 +2,7 @@ import { NapCatPathWrapper } from 'napcat-common/src/path';
import { InitWebUi, WebUiConfig, webUiRuntimePort } from 'napcat-webui-backend/index'; import { InitWebUi, WebUiConfig, webUiRuntimePort } from 'napcat-webui-backend/index';
import { NapCatAdapterManager } from 'napcat-adapter'; import { NapCatAdapterManager } from 'napcat-adapter';
import { NativePacketHandler } from 'napcat-core/packet/handler/client'; import { NativePacketHandler } from 'napcat-core/packet/handler/client';
import { Napi2NativeLoader } from 'napcat-core/packet/handler/napi2nativeLoader';
import { FFmpegService } from 'napcat-core/helper/ffmpeg/ffmpeg'; import { FFmpegService } from 'napcat-core/helper/ffmpeg/ffmpeg';
import { logSubscription, LogWrapper } from 'napcat-core/helper/log'; import { logSubscription, LogWrapper } from 'napcat-core/helper/log';
import { QQBasicInfoWrapper } from '@/napcat-core/helper/qq-basic-info'; import { QQBasicInfoWrapper } from '@/napcat-core/helper/qq-basic-info';
@@ -40,6 +41,7 @@ export async function NCoreInitFramework (
const basicInfoWrapper = new QQBasicInfoWrapper({ logger }); const basicInfoWrapper = new QQBasicInfoWrapper({ logger });
const wrapper = loadQQWrapper(basicInfoWrapper.QQMainPath, basicInfoWrapper.getFullQQVersion()); const wrapper = loadQQWrapper(basicInfoWrapper.QQMainPath, basicInfoWrapper.getFullQQVersion());
const nativePacketHandler = new NativePacketHandler({ logger }); // 初始化 NativePacketHandler 用于后续使用 const nativePacketHandler = new NativePacketHandler({ logger }); // 初始化 NativePacketHandler 用于后续使用
const napi2nativeLoader = new Napi2NativeLoader({ logger }); // 初始化 Napi2NativeLoader 用于后续使用
// nativePacketHandler.onAll((packet) => { // nativePacketHandler.onAll((packet) => {
// console.log('[Packet]', packet.uin, packet.cmd, packet.hex_data); // console.log('[Packet]', packet.uin, packet.cmd, packet.hex_data);
// }); // });
@@ -73,7 +75,7 @@ export async function NCoreInitFramework (
// 过早进入会导致addKernelMsgListener等Listener添加失败 // 过早进入会导致addKernelMsgListener等Listener添加失败
// await sleep(2500); // await sleep(2500);
// 初始化 NapCatFramework // 初始化 NapCatFramework
const loaderObject = new NapCatFramework(wrapper, session, logger, selfInfo, basicInfoWrapper, pathWrapper, nativePacketHandler); const loaderObject = new NapCatFramework(wrapper, session, logger, selfInfo, basicInfoWrapper, pathWrapper, nativePacketHandler, napi2nativeLoader);
await loaderObject.core.initCore(); await loaderObject.core.initCore();
// 启动WebUi // 启动WebUi
@@ -101,10 +103,12 @@ export class NapCatFramework {
selfInfo: SelfInfo, selfInfo: SelfInfo,
basicInfoWrapper: QQBasicInfoWrapper, basicInfoWrapper: QQBasicInfoWrapper,
pathWrapper: NapCatPathWrapper, pathWrapper: NapCatPathWrapper,
packetHandler: NativePacketHandler packetHandler: NativePacketHandler,
napi2nativeLoader: Napi2NativeLoader
) { ) {
this.context = { this.context = {
packetHandler, packetHandler,
napi2nativeLoader,
workingEnv: NapCatCoreWorkingEnv.Framework, workingEnv: NapCatCoreWorkingEnv.Framework,
wrapper, wrapper,
session, session,

View File

@@ -30,6 +30,7 @@ import { NodeIO3MiscListener } from 'napcat-core/listeners/NodeIO3MiscListener';
import { sleep } from 'napcat-common/src/helper'; import { sleep } from 'napcat-common/src/helper';
import { FFmpegService } from '@/napcat-core/helper/ffmpeg/ffmpeg'; import { FFmpegService } from '@/napcat-core/helper/ffmpeg/ffmpeg';
import { NativePacketHandler } from 'napcat-core/packet/handler/client'; import { NativePacketHandler } from 'napcat-core/packet/handler/client';
import { Napi2NativeLoader } from 'napcat-core/packet/handler/napi2nativeLoader';
import { logSubscription, LogWrapper } from '@/napcat-core/helper/log'; import { logSubscription, LogWrapper } from '@/napcat-core/helper/log';
import { proxiedListenerOf } from '@/napcat-core/helper/proxy-handler'; import { proxiedListenerOf } from '@/napcat-core/helper/proxy-handler';
import { QQBasicInfoWrapper } from '@/napcat-core/helper/qq-basic-info'; import { QQBasicInfoWrapper } from '@/napcat-core/helper/qq-basic-info';
@@ -396,6 +397,7 @@ export async function NCoreInitShell () {
const basicInfoWrapper = new QQBasicInfoWrapper({ logger }); const basicInfoWrapper = new QQBasicInfoWrapper({ logger });
const wrapper = loadQQWrapper(basicInfoWrapper.QQMainPath, basicInfoWrapper.getFullQQVersion()); const wrapper = loadQQWrapper(basicInfoWrapper.QQMainPath, basicInfoWrapper.getFullQQVersion());
const nativePacketHandler = new NativePacketHandler({ logger }); // 初始化 NativePacketHandler 用于后续使用 const nativePacketHandler = new NativePacketHandler({ logger }); // 初始化 NativePacketHandler 用于后续使用
const napi2nativeLoader = new Napi2NativeLoader({ logger }); // 初始化 Napi2NativeLoader 用于后续使用
// nativePacketHandler.onAll((packet) => { // nativePacketHandler.onAll((packet) => {
// console.log('[Packet]', packet.uin, packet.cmd, packet.hex_data); // console.log('[Packet]', packet.uin, packet.cmd, packet.hex_data);
@@ -488,7 +490,8 @@ export async function NCoreInitShell () {
selfInfo, selfInfo,
basicInfoWrapper, basicInfoWrapper,
pathWrapper, pathWrapper,
nativePacketHandler nativePacketHandler,
napi2nativeLoader
).InitNapCat(); ).InitNapCat();
} }
@@ -503,10 +506,12 @@ export class NapCatShell {
selfInfo: SelfInfo, selfInfo: SelfInfo,
basicInfoWrapper: QQBasicInfoWrapper, basicInfoWrapper: QQBasicInfoWrapper,
pathWrapper: NapCatPathWrapper, pathWrapper: NapCatPathWrapper,
packetHandler: NativePacketHandler packetHandler: NativePacketHandler,
napi2nativeLoader: Napi2NativeLoader
) { ) {
this.context = { this.context = {
packetHandler, packetHandler,
napi2nativeLoader,
workingEnv: NapCatCoreWorkingEnv.Shell, workingEnv: NapCatCoreWorkingEnv.Shell,
wrapper, wrapper,
session, session,