mirror of
https://github.com/Simplxss/SignerServer.git
synced 2024-11-21 00:37:53 +08:00
Compare commits
41 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
f004ee1f91 | ||
|
a5412fc169 | ||
|
fe0a01f45e | ||
|
0fd58af2ea | ||
|
2237d81dba | ||
|
6f78a9e295 | ||
|
e31a7a02b5 | ||
|
2dd0524050 | ||
|
cf90133c25 | ||
|
57fc689784 | ||
|
2c39499736 | ||
|
52d2fa4851 | ||
|
d120834ac1 | ||
|
d71c73b6c6 | ||
|
7ef0c670f4 | ||
|
0c061dc47d | ||
|
d98bfdda2b | ||
|
8b030c45c5 | ||
|
c39acea3fb | ||
|
848b2643ed | ||
|
598923dc3f | ||
|
d170484afe | ||
|
33c210b7e0 | ||
|
260223e70b | ||
|
1a682ff12d | ||
|
5ba10cc6e1 | ||
|
c924521e94 | ||
|
2778c168c7 | ||
|
0328134d86 | ||
|
72110c1726 | ||
|
90a55d47b3 | ||
|
8ff2eca04a | ||
|
61f0fdedd6 | ||
|
ee8a9bab8d | ||
|
20944c4f95 | ||
|
0474031d93 | ||
|
8828f68988 | ||
|
b66ccb1f72 | ||
|
cd0dfe43b7 | ||
|
871651c579 | ||
|
137ec4fd17 |
52
.github/workflows/build.yml
vendored
52
.github/workflows/build.yml
vendored
@ -1,10 +1,10 @@
|
|||||||
# https://docs.github.com/en/actions/learn-github-actions/contexts
|
# https://docs.github.com/en/actions/learn-github-actions/contexts
|
||||||
|
|
||||||
name: SignerServer
|
name: build
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
pull_request:
|
pull_request:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
workflow_call:
|
workflow_call:
|
||||||
@ -50,6 +50,8 @@ jobs:
|
|||||||
SignerServer.dll
|
SignerServer.dll
|
||||||
load.js
|
load.js
|
||||||
start.sh
|
start.sh
|
||||||
|
start.bat
|
||||||
|
start.command
|
||||||
|
|
||||||
ubuntu:
|
ubuntu:
|
||||||
name: run on ${{ matrix.os }}(${{ matrix.arch }})
|
name: run on ${{ matrix.os }}(${{ matrix.arch }})
|
||||||
@ -91,3 +93,49 @@ jobs:
|
|||||||
libSignerServer.so
|
libSignerServer.so
|
||||||
load.js
|
load.js
|
||||||
start.sh
|
start.sh
|
||||||
|
start.bat
|
||||||
|
start.command
|
||||||
|
|
||||||
|
|
||||||
|
macos:
|
||||||
|
name: run on ${{ matrix.os }}(${{ matrix.arch }})
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [macos-latest]
|
||||||
|
arch: [x64, arm64]
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup cmake
|
||||||
|
uses: lukka/get-cmake@latest
|
||||||
|
|
||||||
|
- name: Build project
|
||||||
|
uses: lukka/run-cmake@v10
|
||||||
|
with:
|
||||||
|
# This is the default path to the CMakeLists.txt along side the
|
||||||
|
# CMakePresets.json. Change if you need have CMakeLists.txt and CMakePresets.json
|
||||||
|
# located elsewhere.
|
||||||
|
cmakeListsTxtPath: '${{ github.workspace }}/CMakeLists.txt'
|
||||||
|
|
||||||
|
# This is the name of the CMakePresets.json's configuration to use to generate
|
||||||
|
# the project files. This configuration leverages the vcpkg.cmake toolchain file to
|
||||||
|
# run vcpkg and install all dependencies specified in vcpkg.json.
|
||||||
|
configurePreset: 'ninja'
|
||||||
|
|
||||||
|
# This is the name of the CMakePresets.json's configuration to build the project.
|
||||||
|
buildPreset: 'ninja-release'
|
||||||
|
|
||||||
|
- run: mv build/ninja/libSignerServer.dylib libSignerServer.dylib
|
||||||
|
|
||||||
|
- name: Upload build
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: SignerServer-${{ matrix.os }}-${{ matrix.arch }}
|
||||||
|
path: |
|
||||||
|
libSignerServer.dylib
|
||||||
|
load.js
|
||||||
|
start.sh
|
||||||
|
start.bat
|
||||||
|
start.command
|
||||||
|
36
.github/workflows/docker-publish.yml
vendored
36
.github/workflows/docker-publish.yml
vendored
@ -10,31 +10,33 @@ env:
|
|||||||
GITHUB_REPO: Simplxss/SignerServer
|
GITHUB_REPO: Simplxss/SignerServer
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
build:
|
||||||
|
uses: ./.github/workflows/build.yml
|
||||||
|
|
||||||
publish-dockerhub:
|
publish-dockerhub:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
needs: build
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
- name: Get artifacts
|
|
||||||
run: |
|
- name: Download All Artifact
|
||||||
bash get_artifacts.sh ${{ secrets.GITHUB_TOKEN }} $(curl "https://api.github.com/repos/NapNeko/NapCatQQ/releases/latest" | jq -r '.tag_name')
|
uses: actions/download-artifact@v4
|
||||||
- name: Set up Docker buildx
|
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v3
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
- name: Login to Docker Hub
|
- name: Login to Docker Hub
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
# Fork from https://github.com/koishijs/boilerplate/blob/master/.github/workflows/docker.yml
|
|
||||||
- name: Run buildx and push
|
- name: Build and push
|
||||||
run: |
|
uses: docker/build-push-action@v5
|
||||||
TAG=$(curl "https://api.github.com/repos/${GITHUB_REPO}/releases/latest" | jq -r '.tag_name')
|
with:
|
||||||
docker buildx build \
|
push: true
|
||||||
--output "type=image,push=true" \
|
tags: user/app:latest
|
||||||
--platform linux/amd64,linux/arm64 \
|
|
||||||
--tag ${DOCKER_REPO}:$TAG \
|
|
||||||
--tag ${DOCKER_REPO}:latest \
|
|
||||||
--file ./Dockerfile \
|
|
||||||
.
|
|
||||||
- name: Docker Hub logout
|
|
||||||
run: docker logout
|
|
41
.github/workflows/release.yml
vendored
41
.github/workflows/release.yml
vendored
@ -5,7 +5,7 @@ name: "release"
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
tags:
|
tags:
|
||||||
- "v*"
|
- "*"
|
||||||
|
|
||||||
permissions: write-all
|
permissions: write-all
|
||||||
|
|
||||||
@ -15,22 +15,27 @@ jobs:
|
|||||||
|
|
||||||
release:
|
release:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: build
|
needs:
|
||||||
|
- build
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Download All Artifact
|
- name: Download All Artifact
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v4
|
||||||
|
|
||||||
- name: Create Release Draft and Upload Artifacts
|
- name: Zip Artifact
|
||||||
uses: softprops/action-gh-release@v1
|
run: |
|
||||||
with:
|
zip -r SignerServer-windows-x64.zip SignerServer-windows-latest-x64.zip/*
|
||||||
name: SignerServer V${{ env.VERSION }}
|
zip -r SignerServer-ubuntu-x64.zip SignerServer-ubuntu-latest-x64.zip/*
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
zip -r SignerServer-ubuntu-arm64.zip SignerServer-ubuntu-latest-arm64.zip/*
|
||||||
body_path: CHANGELOG.md
|
|
||||||
files: |
|
- name: Create Release Draft and Upload Artifacts
|
||||||
SignerServer-windows-latest-x64.zip
|
uses: softprops/action-gh-release@v2
|
||||||
SignerServer-ubuntu-latest-x64.zip
|
with:
|
||||||
SignerServer-ubuntu-latest-arm64.zip
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
draft: true
|
body_path: CHANGELOG.md
|
||||||
|
files: |
|
||||||
|
SignerServer-windows-x64.zip
|
||||||
|
SignerServer-ubuntu-x64.zip
|
||||||
|
SignerServer-ubuntu-arm64.zip
|
||||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,4 +1,5 @@
|
|||||||
.vscode
|
.vscode
|
||||||
build
|
build
|
||||||
*.so
|
*.so
|
||||||
*.dll
|
*.dll
|
||||||
|
*.dylib
|
@ -1,6 +1,6 @@
|
|||||||
# v1.0.0
|
# SignerServer
|
||||||
|
|
||||||
QQ Version: Windows 9.9.9-23424 / Linux 3.2.7-23361
|
QQ Version: Windows 9.9.11-24815 / Linux 3.2.9-24815
|
||||||
|
|
||||||
## 提高系统的稳定性
|
## 提高系统的稳定性
|
||||||
|
|
||||||
|
@ -7,8 +7,6 @@ project(SignerServer)
|
|||||||
if("${CMAKE_SYSTEM_NAME}" STREQUAL "Windows")
|
if("${CMAKE_SYSTEM_NAME}" STREQUAL "Windows")
|
||||||
add_definitions(-D _WIN_PLATFORM_)
|
add_definitions(-D _WIN_PLATFORM_)
|
||||||
|
|
||||||
enable_language(ASM_MASM)
|
|
||||||
|
|
||||||
link_libraries(ws2_32)
|
link_libraries(ws2_32)
|
||||||
elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin")
|
elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin")
|
||||||
add_definitions(-D _MAC_PLATFORM_)
|
add_definitions(-D _MAC_PLATFORM_)
|
||||||
@ -20,16 +18,10 @@ if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "
|
|||||||
add_definitions(-D _X64_ARCH_)
|
add_definitions(-D _X64_ARCH_)
|
||||||
elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86")
|
elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86")
|
||||||
add_definitions(-D _X86_ARCH_)
|
add_definitions(-D _X86_ARCH_)
|
||||||
elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "ARM64")
|
elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64")
|
||||||
add_definitions(-D _ARM64_ARCH_)
|
add_definitions(-D _ARM64_ARCH_)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
file(GLOB SOURCE_FILES "./src/*.cpp" "./src/*.asm")
|
file(GLOB SOURCE_FILES "./src/*.cpp")
|
||||||
|
|
||||||
add_library(SignerServer SHARED ${SOURCE_FILES})
|
add_library(SignerServer SHARED ${SOURCE_FILES})
|
||||||
|
|
||||||
if(MSVC)
|
|
||||||
target_link_options(SignerServer PRIVATE
|
|
||||||
/DEF:${CMAKE_CURRENT_SOURCE_DIR}/version.def
|
|
||||||
)
|
|
||||||
endif()
|
|
37
Dockerfile
37
Dockerfile
@ -1,6 +1,7 @@
|
|||||||
FROM mlikiowa/napcat-docker:base
|
FROM ubuntu:22.04
|
||||||
|
|
||||||
WORKDIR /usr/src/app
|
# 设置环境变量
|
||||||
|
ENV DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
COPY SignerServer-ubuntu-latest-x64.zip .
|
COPY SignerServer-ubuntu-latest-x64.zip .
|
||||||
|
|
||||||
@ -12,13 +13,31 @@ RUN arch=$(arch | sed s/aarch64/arm64/ | sed s/x86_64/amd64/) && \
|
|||||||
# 安装 SignerServer
|
# 安装 SignerServer
|
||||||
RUN arch=$(arch | sed s/aarch64/arm64/ | sed s/x86_64/x64/) && \
|
RUN arch=$(arch | sed s/aarch64/arm64/ | sed s/x86_64/x64/) && \
|
||||||
unzip SignerServer-ubuntu-latest-${arch}.zip && \
|
unzip SignerServer-ubuntu-latest-${arch}.zip && \
|
||||||
chrom +x start.sh
|
chrom +x start.sh && \
|
||||||
|
apt-get update && apt-get install -y \
|
||||||
# 配置 supervisord
|
libnss3 \
|
||||||
RUN echo "[supervisord]" > /etc/supervisord.conf && \
|
libnotify4 \
|
||||||
echo "nodaemon=true" >> /etc/supervisord.conf && \
|
libsecret-1-0 \
|
||||||
echo "[program:napcat]" >> /etc/supervisord.conf && \
|
libgbm1 \
|
||||||
echo "command=COMMAND" >> /etc/supervisord.conf
|
libasound2 \
|
||||||
|
fonts-wqy-zenhei \
|
||||||
|
gnutls-bin \
|
||||||
|
libglib2.0-dev \
|
||||||
|
libdbus-1-3 \
|
||||||
|
libgtk-3-0 \
|
||||||
|
libxss1 \
|
||||||
|
libxtst6 \
|
||||||
|
libatspi2.0-0 \
|
||||||
|
libx11-xcb1 \
|
||||||
|
ffmpeg \
|
||||||
|
unzip \
|
||||||
|
curl && \
|
||||||
|
apt autoremove -y && \
|
||||||
|
apt clean && \
|
||||||
|
rm -rf \
|
||||||
|
/var/lib/apt/lists/* \
|
||||||
|
/tmp/* \
|
||||||
|
/var/tmp/*
|
||||||
|
|
||||||
ENTRYPOINT ["sh", "start.sh"]
|
ENTRYPOINT ["sh", "start.sh"]
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
#ifndef CPPHTTPLIB_HTTPLIB_H
|
#ifndef CPPHTTPLIB_HTTPLIB_H
|
||||||
#define CPPHTTPLIB_HTTPLIB_H
|
#define CPPHTTPLIB_HTTPLIB_H
|
||||||
|
|
||||||
#define CPPHTTPLIB_VERSION "0.15.3"
|
#define CPPHTTPLIB_VERSION "0.16.0"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Configuration
|
* Configuration
|
||||||
@ -726,6 +726,10 @@ private:
|
|||||||
assert(true == static_cast<bool>(fn));
|
assert(true == static_cast<bool>(fn));
|
||||||
fn();
|
fn();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||||
|
OPENSSL_thread_stop ();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
ThreadPool &pool_;
|
ThreadPool &pool_;
|
||||||
@ -1819,6 +1823,9 @@ public:
|
|||||||
bool is_valid() const override;
|
bool is_valid() const override;
|
||||||
|
|
||||||
SSL_CTX *ssl_context() const;
|
SSL_CTX *ssl_context() const;
|
||||||
|
|
||||||
|
void update_certs (X509 *cert, EVP_PKEY *private_key,
|
||||||
|
X509_STORE *client_ca_cert_store = nullptr);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool process_and_close_socket(socket_t sock) override;
|
bool process_and_close_socket(socket_t sock) override;
|
||||||
@ -2825,15 +2832,25 @@ inline bool mmap::open(const char *path) {
|
|||||||
if (!::GetFileSizeEx(hFile_, &size)) { return false; }
|
if (!::GetFileSizeEx(hFile_, &size)) { return false; }
|
||||||
size_ = static_cast<size_t>(size.QuadPart);
|
size_ = static_cast<size_t>(size.QuadPart);
|
||||||
|
|
||||||
|
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
|
||||||
hMapping_ =
|
hMapping_ =
|
||||||
::CreateFileMappingFromApp(hFile_, NULL, PAGE_READONLY, size_, NULL);
|
::CreateFileMappingFromApp(hFile_, NULL, PAGE_READONLY, size_, NULL);
|
||||||
|
#else
|
||||||
|
hMapping_ =
|
||||||
|
::CreateFileMappingW(hFile_, NULL, PAGE_READONLY, size.HighPart,
|
||||||
|
size.LowPart, NULL);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (hMapping_ == NULL) {
|
if (hMapping_ == NULL) {
|
||||||
close();
|
close();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
|
||||||
addr_ = ::MapViewOfFileFromApp(hMapping_, FILE_MAP_READ, 0, 0);
|
addr_ = ::MapViewOfFileFromApp(hMapping_, FILE_MAP_READ, 0, 0);
|
||||||
|
#else
|
||||||
|
addr_ = ::MapViewOfFile(hMapping_, FILE_MAP_READ, 0, 0, 0);
|
||||||
|
#endif
|
||||||
#else
|
#else
|
||||||
fd_ = ::open(path, O_RDONLY);
|
fd_ = ::open(path, O_RDONLY);
|
||||||
if (fd_ == -1) { return false; }
|
if (fd_ == -1) { return false; }
|
||||||
@ -4935,7 +4952,7 @@ get_range_offset_and_length(Range r, size_t content_length) {
|
|||||||
assert(0 <= r.first && r.first < static_cast<ssize_t>(content_length));
|
assert(0 <= r.first && r.first < static_cast<ssize_t>(content_length));
|
||||||
assert(r.first <= r.second &&
|
assert(r.first <= r.second &&
|
||||||
r.second < static_cast<ssize_t>(content_length));
|
r.second < static_cast<ssize_t>(content_length));
|
||||||
|
(void)(content_length);
|
||||||
return std::make_pair(r.first, static_cast<size_t>(r.second - r.first) + 1);
|
return std::make_pair(r.first, static_cast<size_t>(r.second - r.first) + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7268,7 +7285,7 @@ inline bool ClientImpl::redirect(Request &req, Response &res, Error &error) {
|
|||||||
if (location.empty()) { return false; }
|
if (location.empty()) { return false; }
|
||||||
|
|
||||||
const static std::regex re(
|
const static std::regex re(
|
||||||
R"((?:(https?):)?(?://(?:\[([\d:]+)\]|([^:/?#]+))(?::(\d+))?)?([^?#]*)(\?[^#]*)?(?:#.*)?)");
|
R"((?:(https?):)?(?://(?:\[([a-fA-F\d:]+)\]|([^:/?#]+))(?::(\d+))?)?([^?#]*)(\?[^#]*)?(?:#.*)?)");
|
||||||
|
|
||||||
std::smatch m;
|
std::smatch m;
|
||||||
if (!std::regex_match(location, m, re)) { return false; }
|
if (!std::regex_match(location, m, re)) { return false; }
|
||||||
@ -8753,6 +8770,19 @@ inline bool SSLServer::is_valid() const { return ctx_; }
|
|||||||
|
|
||||||
inline SSL_CTX *SSLServer::ssl_context() const { return ctx_; }
|
inline SSL_CTX *SSLServer::ssl_context() const { return ctx_; }
|
||||||
|
|
||||||
|
inline void SSLServer::update_certs (X509 *cert, EVP_PKEY *private_key,
|
||||||
|
X509_STORE *client_ca_cert_store) {
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> guard(ctx_mutex_);
|
||||||
|
|
||||||
|
SSL_CTX_use_certificate (ctx_, cert);
|
||||||
|
SSL_CTX_use_PrivateKey (ctx_, private_key);
|
||||||
|
|
||||||
|
if (client_ca_cert_store != nullptr) {
|
||||||
|
SSL_CTX_set_cert_store (ctx_, client_ca_cert_store);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
inline bool SSLServer::process_and_close_socket(socket_t sock) {
|
inline bool SSLServer::process_and_close_socket(socket_t sock) {
|
||||||
auto ssl = detail::ssl_new(
|
auto ssl = detail::ssl_new(
|
||||||
sock, ctx_, ctx_mutex_,
|
sock, ctx_, ctx_mutex_,
|
||||||
@ -9213,7 +9243,7 @@ inline Client::Client(const std::string &scheme_host_port,
|
|||||||
const std::string &client_cert_path,
|
const std::string &client_cert_path,
|
||||||
const std::string &client_key_path) {
|
const std::string &client_key_path) {
|
||||||
const static std::regex re(
|
const static std::regex re(
|
||||||
R"((?:([a-z]+):\/\/)?(?:\[([\d:]+)\]|([^:/?#]+))(?::(\d+))?)");
|
R"((?:([a-z]+):\/\/)?(?:\[([a-fA-F\d:]+)\]|([^:/?#]+))(?::(\d+))?)");
|
||||||
|
|
||||||
std::smatch m;
|
std::smatch m;
|
||||||
if (std::regex_match(scheme_host_port, m, re)) {
|
if (std::regex_match(scheme_host_port, m, re)) {
|
||||||
@ -9250,6 +9280,8 @@ inline Client::Client(const std::string &scheme_host_port,
|
|||||||
client_key_path);
|
client_key_path);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// NOTE: Update TEST(UniversalClientImplTest, Ipv6LiteralAddress)
|
||||||
|
// if port param below changes.
|
||||||
cli_ = detail::make_unique<ClientImpl>(scheme_host_port, 80,
|
cli_ = detail::make_unique<ClientImpl>(scheme_host_port, 80,
|
||||||
client_cert_path, client_key_path);
|
client_cert_path, client_key_path);
|
||||||
}
|
}
|
||||||
|
199
include/moehoo/hook.h
Normal file
199
include/moehoo/hook.h
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
#ifndef _HOOK_H_
|
||||||
|
#define _HOOK_H_
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#if defined(_WIN_PLATFORM_)
|
||||||
|
#include <Windows.h>
|
||||||
|
#elif defined(_LINUX_PLATFORM_) || defined(_MAC_PLATFORM_)
|
||||||
|
#include "proc_maps.h"
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace moehoo
|
||||||
|
{
|
||||||
|
void *get_call_address(uint8_t *ptr);
|
||||||
|
void *search_and_fill_jump(uint64_t baseAddress, void *targetAddress);
|
||||||
|
bool hook(uint8_t *callAddr, void *lpFunction);
|
||||||
|
} // namespace moehoo
|
||||||
|
|
||||||
|
inline void *moehoo::get_call_address(uint8_t *ptr)
|
||||||
|
{
|
||||||
|
// 读取操作码
|
||||||
|
if (ptr[0] != 0xE8)
|
||||||
|
{
|
||||||
|
printf("Not a call instruction!\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 读取相对偏移量
|
||||||
|
int32_t relativeOffset = *reinterpret_cast<int32_t *>(ptr + 1);
|
||||||
|
|
||||||
|
// 计算函数地址
|
||||||
|
uint8_t *callAddress = ptr + 5; // call 指令占 5 个字节
|
||||||
|
void *functionAddress = callAddress + relativeOffset;
|
||||||
|
|
||||||
|
return reinterpret_cast<void *>(functionAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void *moehoo::search_and_fill_jump(uint64_t baseAddress, void *targetAddress)
|
||||||
|
{
|
||||||
|
uint8_t jumpInstruction[] = {
|
||||||
|
0x49, 0xBB,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x41, 0xFF, 0xE3};
|
||||||
|
|
||||||
|
memcpy(jumpInstruction + 2, &targetAddress, 8);
|
||||||
|
|
||||||
|
// Iterate through memory regions
|
||||||
|
uint64_t searchStart = baseAddress - 0x7fffffff;
|
||||||
|
uint64_t searchEnd = baseAddress + 0x7fffffff;
|
||||||
|
|
||||||
|
#if defined(_WIN_PLATFORM_)
|
||||||
|
while (searchStart < searchEnd - sizeof(jumpInstruction))
|
||||||
|
{
|
||||||
|
MEMORY_BASIC_INFORMATION mbi;
|
||||||
|
if (VirtualQuery(reinterpret_cast<void *>(searchStart), &mbi, sizeof(mbi)) == 0)
|
||||||
|
break;
|
||||||
|
if (mbi.State == MEM_COMMIT)
|
||||||
|
{
|
||||||
|
for (char *addr = static_cast<char *>(mbi.BaseAddress); addr < static_cast<char *>(mbi.BaseAddress) + mbi.RegionSize - 1024 * 5; ++addr)
|
||||||
|
{
|
||||||
|
|
||||||
|
bool isFree = true;
|
||||||
|
for (int i = 0; i < 1024 * 5; ++i)
|
||||||
|
{
|
||||||
|
if (addr[i] != 0)
|
||||||
|
{
|
||||||
|
isFree = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isFree)
|
||||||
|
{
|
||||||
|
DWORD oldProtect;
|
||||||
|
addr += 0x200;
|
||||||
|
// printf("addr: %p\n", addr);
|
||||||
|
|
||||||
|
if (!VirtualProtect(addr, sizeof(jumpInstruction), PAGE_EXECUTE_READWRITE, &oldProtect))
|
||||||
|
break;
|
||||||
|
memcpy(addr, jumpInstruction, sizeof(jumpInstruction));
|
||||||
|
if (!VirtualProtect(addr, sizeof(jumpInstruction), PAGE_EXECUTE_READ, &oldProtect))
|
||||||
|
break;
|
||||||
|
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
searchStart += mbi.RegionSize;
|
||||||
|
}
|
||||||
|
#elif defined(_LINUX_PLATFORM_) || defined(_MAC_PLATFORM_)
|
||||||
|
// 保证地址对齐
|
||||||
|
searchStart &= 0xfffffffffffff000;
|
||||||
|
searchStart += 0x1000;
|
||||||
|
searchEnd &= 0xfffffffffffff000;
|
||||||
|
|
||||||
|
auto pmap = hak::get_maps();
|
||||||
|
do
|
||||||
|
{
|
||||||
|
auto fpmap = pmap;
|
||||||
|
pmap = fpmap->next();
|
||||||
|
if (std::min(pmap->start(), searchEnd) - std::max(fpmap->end(), searchStart) > 0x2000) // 搜索一片 0x2000 大小的空区域
|
||||||
|
{
|
||||||
|
void *addr = mmap(reinterpret_cast<void *>(std::max(fpmap->end(), searchStart)), 0x2000, PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||||
|
// printf("addr: %p\n", addr);
|
||||||
|
if (addr == MAP_FAILED)
|
||||||
|
{
|
||||||
|
printf("mmap failed\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (reinterpret_cast<uint64_t>(addr) > searchEnd - sizeof(jumpInstruction))
|
||||||
|
{
|
||||||
|
munmap(addr, 0x2000);
|
||||||
|
printf("addr > searchEnd\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
memcpy(addr, jumpInstruction, sizeof(jumpInstruction));
|
||||||
|
if (mprotect(addr, 0x2000, PROT_READ | PROT_EXEC) == -1) // 设置内存 r-w
|
||||||
|
{
|
||||||
|
munmap(addr, 0x2000);
|
||||||
|
printf("mprotect failed\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
} while (pmap->next() != nullptr);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool moehoo::hook(uint8_t *callAddr, void *lpFunction)
|
||||||
|
{
|
||||||
|
uint64_t startAddr = reinterpret_cast<uint64_t>(callAddr) + 5;
|
||||||
|
int64_t distance = reinterpret_cast<uint64_t>(lpFunction) - startAddr;
|
||||||
|
#if defined(_WIN_PLATFORM_)
|
||||||
|
// printf("Hooking %p to %p, distance: %lld\n", callAddr, lpFunction, distance);
|
||||||
|
|
||||||
|
DWORD oldProtect;
|
||||||
|
DWORD reProtect;
|
||||||
|
if (!VirtualProtect(callAddr, 10, PAGE_EXECUTE_READWRITE, &oldProtect))
|
||||||
|
{
|
||||||
|
printf("VirtualProtect failed\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (distance < INT32_MIN || distance > INT32_MAX)
|
||||||
|
{
|
||||||
|
void *new_ret = search_and_fill_jump(startAddr, lpFunction);
|
||||||
|
if (new_ret == nullptr)
|
||||||
|
{
|
||||||
|
printf("Can't find a place to jump\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
distance = reinterpret_cast<uint64_t>(new_ret) - startAddr;
|
||||||
|
// printf("new_ret: %p, new_distance: %lld\n", new_ret, distance);
|
||||||
|
}
|
||||||
|
// 直接进行小跳转
|
||||||
|
memcpy(callAddr + 1, reinterpret_cast<int32_t *>(&distance), 4); // 修改 call 地址
|
||||||
|
if (!VirtualProtect(callAddr, 10, oldProtect, &reProtect)) // 恢复原来的内存保护属性
|
||||||
|
{
|
||||||
|
std::cout << GetLastError() << "/" << callAddr << "/" << oldProtect << "/" << reProtect;
|
||||||
|
printf("VirtualProtect failed\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
#elif defined(_LINUX_PLATFORM_) || defined(_MAC_PLATFORM_)
|
||||||
|
// printf("Hooking %p to %p, distance: %ld\n", callAddr, lpFunction, distance);
|
||||||
|
|
||||||
|
auto get_page_addr = [](void *addr) -> void *
|
||||||
|
{
|
||||||
|
return (void *)((uintptr_t)addr & ~(getpagesize() - 1));
|
||||||
|
};
|
||||||
|
|
||||||
|
if (mprotect(get_page_addr(callAddr), 2 * getpagesize(), PROT_READ | PROT_WRITE | PROT_EXEC) == -1) // 设置内存可写 两倍 pagesize 防止处于页边界
|
||||||
|
{
|
||||||
|
printf("mprotect failed\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (distance < INT32_MIN || distance > INT32_MAX)
|
||||||
|
{
|
||||||
|
void *new_ret = search_and_fill_jump(startAddr, lpFunction);
|
||||||
|
if (new_ret == nullptr)
|
||||||
|
{
|
||||||
|
printf("Can't find a place to jump\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
distance = reinterpret_cast<uint64_t>(new_ret) - startAddr;
|
||||||
|
// printf("new_ret: %p, new_distance: %ld\n", new_ret, distance);
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(callAddr + 1, reinterpret_cast<int32_t *>(&distance), 4); // 修改 call 地址
|
||||||
|
if (mprotect(get_page_addr(callAddr), 2 * getpagesize(), PROT_READ | PROT_EXEC) == -1) // 还原内存保护属性
|
||||||
|
{
|
||||||
|
printf("mprotect failed\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // _HOOK_H_
|
182
include/moehoo/proc_maps.h
Normal file
182
include/moehoo/proc_maps.h
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
#ifndef PROC_MAPS_H
|
||||||
|
#define PROC_MAPS_H
|
||||||
|
|
||||||
|
#if defined(_LINUX_PLATFORM_) || defined(_MAC_PLATFORM_)
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
#include <fstream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
namespace hak
|
||||||
|
{
|
||||||
|
class proc_maps : public std::enable_shared_from_this<proc_maps>
|
||||||
|
{
|
||||||
|
std::shared_ptr<proc_maps> _head;
|
||||||
|
std::shared_ptr<proc_maps> _tail;
|
||||||
|
|
||||||
|
uint64_t _start;
|
||||||
|
uint64_t _end;
|
||||||
|
|
||||||
|
public:
|
||||||
|
proc_maps(uint64_t start, uint64_t end);
|
||||||
|
|
||||||
|
bool readable = false;
|
||||||
|
bool writable = false;
|
||||||
|
bool executable = false;
|
||||||
|
bool is_private = false;
|
||||||
|
uint32_t offset = 0;
|
||||||
|
std::string module_name;
|
||||||
|
|
||||||
|
void insert(std::shared_ptr<proc_maps> maps);
|
||||||
|
|
||||||
|
void remove();
|
||||||
|
|
||||||
|
// The speed of this api is not very fast~~~!
|
||||||
|
auto size() -> size_t;
|
||||||
|
|
||||||
|
[[nodiscard]] auto start() const -> uint64_t;
|
||||||
|
|
||||||
|
[[nodiscard]] auto end() const -> uint64_t;
|
||||||
|
|
||||||
|
auto last() -> std::shared_ptr<proc_maps>;
|
||||||
|
|
||||||
|
auto next() -> std::shared_ptr<proc_maps> &;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto get_maps(pid_t pid = 0) -> std::shared_ptr<proc_maps>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "proc_maps.h"
|
||||||
|
|
||||||
|
inline hak::proc_maps::proc_maps(uint64_t start, uint64_t end)
|
||||||
|
{
|
||||||
|
this->_start = start;
|
||||||
|
this->_end = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void hak::proc_maps::insert(std::shared_ptr<hak::proc_maps> maps)
|
||||||
|
{ // NOLINT(*-unnecessary-value-param)
|
||||||
|
if (maps == shared_from_this())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this->_tail == nullptr)
|
||||||
|
{
|
||||||
|
this->_tail = maps;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto temp = this->_tail;
|
||||||
|
maps->_head = shared_from_this();
|
||||||
|
maps->last()->_tail = temp;
|
||||||
|
this->_tail = maps;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void hak::proc_maps::remove()
|
||||||
|
{
|
||||||
|
_head->_tail = _tail;
|
||||||
|
_tail->_head = _head;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline auto hak::proc_maps::size() -> size_t
|
||||||
|
{
|
||||||
|
size_t size = 1;
|
||||||
|
auto curr = shared_from_this();
|
||||||
|
while ((curr = curr->next()) != nullptr)
|
||||||
|
{
|
||||||
|
size++;
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline auto hak::proc_maps::start() const -> uint64_t
|
||||||
|
{
|
||||||
|
return _start;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline auto hak::proc_maps::end() const -> uint64_t
|
||||||
|
{
|
||||||
|
return _end;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline auto hak::proc_maps::next() -> std::shared_ptr<hak::proc_maps> &
|
||||||
|
{
|
||||||
|
return _tail;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline auto hak::proc_maps::last() -> std::shared_ptr<hak::proc_maps>
|
||||||
|
{
|
||||||
|
auto curr = shared_from_this();
|
||||||
|
std::shared_ptr<proc_maps> result = curr;
|
||||||
|
while ((curr = curr->next()) != nullptr)
|
||||||
|
{
|
||||||
|
result = curr;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void llex_maps(pid_t pid, const std::function<void(std::shared_ptr<hak::proc_maps>)> &callback)
|
||||||
|
{
|
||||||
|
std::ifstream maps(std::string("/proc/") + (pid == 0 ? std::string("self") : std::to_string(pid)) + "/maps");
|
||||||
|
if (!maps.is_open())
|
||||||
|
{
|
||||||
|
throw std::exception();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string line;
|
||||||
|
bool last_is_cd = false;
|
||||||
|
while (getline(maps, line))
|
||||||
|
{
|
||||||
|
std::istringstream iss(line);
|
||||||
|
std::vector<std::string> tokens;
|
||||||
|
std::string token;
|
||||||
|
|
||||||
|
while (getline(iss, token, ' '))
|
||||||
|
{
|
||||||
|
tokens.push_back(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto address = tokens[0];
|
||||||
|
std::string::size_type pos = address.find('-');
|
||||||
|
uint64_t start_addr = std::stoull(address.substr(0, pos), nullptr, 16);
|
||||||
|
uint64_t end_addr = std::stoull(address.substr(pos + 1), nullptr, 16);
|
||||||
|
auto pmaps = std::make_shared<hak::proc_maps>(start_addr, end_addr);
|
||||||
|
auto perms = tokens[1];
|
||||||
|
pmaps->readable = perms[0] == 'r';
|
||||||
|
pmaps->writable = perms[1] == 'w';
|
||||||
|
pmaps->executable = perms[2] == 'x';
|
||||||
|
pmaps->is_private = perms[3] == 'p';
|
||||||
|
pmaps->offset = std::stoull(tokens[2], nullptr, 16);
|
||||||
|
if (tokens.size() > 5)
|
||||||
|
{
|
||||||
|
for (int i = 5; i < tokens.size(); i++)
|
||||||
|
{
|
||||||
|
pmaps->module_name += tokens[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
callback(pmaps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline auto hak::get_maps(pid_t pid) -> std::shared_ptr<proc_maps>
|
||||||
|
{
|
||||||
|
std::shared_ptr<proc_maps> head;
|
||||||
|
llex_maps(pid, [&](std::shared_ptr<proc_maps> maps) { // NOLINT(*-unnecessary-value-param)
|
||||||
|
if (head == nullptr)
|
||||||
|
{
|
||||||
|
head.swap(maps);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
head->insert(maps);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return head;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // PROC_MAPS_H
|
22
load.js
22
load.js
@ -3,17 +3,19 @@ const os = require('node:os');
|
|||||||
|
|
||||||
const exePath = path.dirname(process.execPath);
|
const exePath = path.dirname(process.execPath);
|
||||||
|
|
||||||
var QQWrapper;
|
let QQWrapper, version, appid, qua;
|
||||||
const qqPkgInfo = require(path.join(exePath, "resources/app/package.json"));
|
|
||||||
var appid;
|
|
||||||
var qua;
|
|
||||||
if (os.platform() === "win32") {
|
if (os.platform() === "win32") {
|
||||||
QQWrapper = require(path.join(exePath, "resources/app/versions", qqPkgInfo.version, "wrapper.node"));
|
const versionConfig = require(path.join(exePath, "resources/app/versions/config.json"));
|
||||||
appid = "537213803";
|
version = versionConfig.curVersion;
|
||||||
qua = `V1_WIN_NQ_${qqVersionConfigInfo.curVersion.replace("-", "_")}_GW_B`;
|
QQWrapper = require(path.join(exePath, "resources/app/versions", version, "wrapper.node"));
|
||||||
|
appid = "537226655"; // 9.9.12-25234
|
||||||
|
qua = `V1_WIN_NQ_${version.replace("-", "_")}_GW_B`;
|
||||||
} else {
|
} else {
|
||||||
|
const qqPkgInfo = require(path.join(exePath, "resources/app/package.json"));
|
||||||
QQWrapper = require(path.join(exePath, "resources/app/wrapper.node"));
|
QQWrapper = require(path.join(exePath, "resources/app/wrapper.node"));
|
||||||
appid = "537213827";
|
version = qqPkgInfo.version;
|
||||||
|
appid = "537226441";
|
||||||
qua = qqPkgInfo.qua;
|
qua = qqPkgInfo.qua;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,7 +45,7 @@ engine.initWithDeskTopConfig({
|
|||||||
base_path_prefix: "",
|
base_path_prefix: "",
|
||||||
platform_type: 3,
|
platform_type: 3,
|
||||||
app_type: 4,
|
app_type: 4,
|
||||||
app_version: qqPkgInfo.version,
|
app_version: version,
|
||||||
os_version: os.release(),
|
os_version: os.release(),
|
||||||
use_xlog: true,
|
use_xlog: true,
|
||||||
qua: qua,
|
qua: qua,
|
||||||
@ -59,6 +61,6 @@ loginService.initConfig({
|
|||||||
appid: appid,
|
appid: appid,
|
||||||
platVer: os.release(),
|
platVer: os.release(),
|
||||||
commonPath: dataPathGlobal,
|
commonPath: dataPathGlobal,
|
||||||
clientVer: qqPkgInfo.version,
|
clientVer: version,
|
||||||
hostName: os.hostname()
|
hostName: os.hostname()
|
||||||
});
|
});
|
@ -1,29 +0,0 @@
|
|||||||
#if defined(_WIN_PLATFORM_)
|
|
||||||
|
|
||||||
#include "exports.h"
|
|
||||||
#include <filesystem>
|
|
||||||
|
|
||||||
FARPROC OriginalFuncs_version[17];
|
|
||||||
|
|
||||||
void Exports::Load() {
|
|
||||||
char szSystemDirectory[MAX_PATH]{};
|
|
||||||
GetSystemDirectoryA(szSystemDirectory, MAX_PATH);
|
|
||||||
|
|
||||||
std::string OriginalPath = szSystemDirectory;
|
|
||||||
OriginalPath += "\\version.dll";
|
|
||||||
|
|
||||||
HMODULE version = LoadLibraryA(OriginalPath.c_str());
|
|
||||||
// load version.dll from system32
|
|
||||||
if (!version) {
|
|
||||||
throw std::runtime_error("Failed to load version.dll from system32\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
// get addresses of original functions
|
|
||||||
for (int i = 0; i < 17; i++) {
|
|
||||||
OriginalFuncs_version[i] = GetProcAddress(version, ExportNames_version[i].c_str());
|
|
||||||
if (!OriginalFuncs_version[i]) {
|
|
||||||
throw std::runtime_error("Failed to get address of " + ExportNames_version[i] + "\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
@ -1,30 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <Windows.h>
|
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
extern "C" FARPROC OriginalFuncs_version[17];
|
|
||||||
|
|
||||||
inline std::vector<std::string> ExportNames_version = {
|
|
||||||
"GetFileVersionInfoA",
|
|
||||||
"GetFileVersionInfoByHandle",
|
|
||||||
"GetFileVersionInfoExA",
|
|
||||||
"GetFileVersionInfoExW",
|
|
||||||
"GetFileVersionInfoSizeA",
|
|
||||||
"GetFileVersionInfoSizeExA",
|
|
||||||
"GetFileVersionInfoSizeExW",
|
|
||||||
"GetFileVersionInfoSizeW",
|
|
||||||
"GetFileVersionInfoW",
|
|
||||||
"VerFindFileA",
|
|
||||||
"VerFindFileW",
|
|
||||||
"VerInstallFileA",
|
|
||||||
"VerInstallFileW",
|
|
||||||
"VerLanguageNameA",
|
|
||||||
"VerLanguageNameW",
|
|
||||||
"VerQueryValueA",
|
|
||||||
"VerQueryValueW"
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace Exports {
|
|
||||||
void Load();
|
|
||||||
}
|
|
@ -1,21 +1,62 @@
|
|||||||
#if defined(_WIN_PLATFORM_)
|
#if defined(_WIN_PLATFORM_)
|
||||||
|
#include "run_as_node.h"
|
||||||
|
|
||||||
#include "exports.h"
|
// bool TlsOnce = false;
|
||||||
|
// // this runs way before dllmain
|
||||||
|
// void __stdcall TlsCallback(PVOID hModule, DWORD fdwReason, PVOID pContext)
|
||||||
|
// {
|
||||||
|
// if (!TlsOnce)
|
||||||
|
// {
|
||||||
|
// try
|
||||||
|
// {
|
||||||
|
// RunAsNode::Init();
|
||||||
|
// }
|
||||||
|
// catch (std::exception &e)
|
||||||
|
// {
|
||||||
|
// printf("Failed to Init RunAsNode: %s\n", e.what());
|
||||||
|
// }
|
||||||
|
// TlsOnce = true;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
bool TlsOnce = false;
|
// #pragma comment(linker, "/INCLUDE:_tls_used")
|
||||||
// this runs way before dllmain
|
// #pragma comment(linker, "/INCLUDE:tls_callback_func")
|
||||||
void __stdcall TlsCallback(PVOID hModule, DWORD fdwReason, PVOID pContext) {
|
// #pragma const_seg(".CRT$XLF")
|
||||||
if (!TlsOnce) {
|
// EXTERN_C const PIMAGE_TLS_CALLBACK tls_callback_func = TlsCallback;
|
||||||
// for version.dll proxy
|
|
||||||
// load exports as early as possible
|
|
||||||
Exports::Load();
|
|
||||||
TlsOnce = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma comment (linker, "/INCLUDE:_tls_used")
|
// // version.dll DLLHijack
|
||||||
#pragma comment (linker, "/INCLUDE:tls_callback_func")
|
// extern "C" __declspec(dllexport) void GetFileVersionInfoA() {}
|
||||||
#pragma const_seg(".CRT$XLF")
|
// extern "C" __declspec(dllexport) void GetFileVersionInfoByHandle() {}
|
||||||
EXTERN_C const PIMAGE_TLS_CALLBACK tls_callback_func = TlsCallback;
|
// extern "C" __declspec(dllexport) void GetFileVersionInfoExA() {}
|
||||||
|
// extern "C" __declspec(dllexport) void GetFileVersionInfoExW() {}
|
||||||
|
// extern "C" __declspec(dllexport) void GetFileVersionInfoSizeA() {}
|
||||||
|
// extern "C" __declspec(dllexport) void GetFileVersionInfoSizeExA() {}
|
||||||
|
// extern "C" __declspec(dllexport) void GetFileVersionInfoSizeExW() {}
|
||||||
|
// extern "C" __declspec(dllexport) void GetFileVersionInfoSizeW() {}
|
||||||
|
// extern "C" __declspec(dllexport) void GetFileVersionInfoW() {}
|
||||||
|
// extern "C" __declspec(dllexport) void VerFindFileA() {}
|
||||||
|
// extern "C" __declspec(dllexport) void VerFindFileW() {}
|
||||||
|
// extern "C" __declspec(dllexport) void VerInstallFileA() {}
|
||||||
|
// extern "C" __declspec(dllexport) void VerInstallFileW() {}
|
||||||
|
// extern "C" __declspec(dllexport) void VerLanguageNameA() {}
|
||||||
|
// extern "C" __declspec(dllexport) void VerLanguageNameW() {}
|
||||||
|
// extern "C" __declspec(dllexport) void VerQueryValueA() {}
|
||||||
|
// extern "C" __declspec(dllexport) void VerQueryValueW() {}
|
||||||
|
|
||||||
|
// dbghelp.dll DLLHijack
|
||||||
|
extern "C" __declspec(dllexport) void StackWalk64() {}
|
||||||
|
extern "C" __declspec(dllexport) void SymCleanup() {}
|
||||||
|
extern "C" __declspec(dllexport) void SymFromAddr() {}
|
||||||
|
extern "C" __declspec(dllexport) void SymFunctionTableAccess64() {}
|
||||||
|
extern "C" __declspec(dllexport) void SymGetLineFromAddr64() {}
|
||||||
|
extern "C" __declspec(dllexport) void SymGetModuleBase64() {}
|
||||||
|
extern "C" __declspec(dllexport) void SymGetModuleInfo64() {}
|
||||||
|
extern "C" __declspec(dllexport) void SymGetSymFromAddr64() {}
|
||||||
|
extern "C" __declspec(dllexport) void SymGetSearchPathW() {}
|
||||||
|
extern "C" __declspec(dllexport) void SymInitialize() {}
|
||||||
|
extern "C" __declspec(dllexport) void SymSetOptions() {}
|
||||||
|
extern "C" __declspec(dllexport) void SymGetOptions() {}
|
||||||
|
extern "C" __declspec(dllexport) void SymSetSearchPathW() {}
|
||||||
|
extern "C" __declspec(dllexport) void UnDecorateSymbolName() {}
|
||||||
|
extern "C" __declspec(dllexport) void MiniDumpWriteDump() {}
|
||||||
#endif
|
#endif
|
170
src/main.cpp
170
src/main.cpp
@ -1,3 +1,171 @@
|
|||||||
#include "server.h"
|
#include "server.h"
|
||||||
|
|
||||||
Server server(1145);
|
#include "../include/rapidjson/document.h"
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
void init()
|
||||||
|
{
|
||||||
|
#if defined(_WIN_PLATFORM_)
|
||||||
|
std::string version = "9.9.12-25300";
|
||||||
|
try
|
||||||
|
{
|
||||||
|
TCHAR pathm[MAX_PATH];
|
||||||
|
GetModuleFileName(NULL, pathm, MAX_PATH);
|
||||||
|
std::filesystem::path path = pathm;
|
||||||
|
path = path.parent_path().append("resources\\app\\versions\\config.json");
|
||||||
|
std::ifstream versionConfig(path.wstring());
|
||||||
|
if (versionConfig.is_open())
|
||||||
|
{
|
||||||
|
std::stringstream versionConfigStream;
|
||||||
|
versionConfigStream << versionConfig.rdbuf();
|
||||||
|
versionConfig.close();
|
||||||
|
rapidjson::Document doc;
|
||||||
|
doc.Parse(versionConfigStream.str().c_str(), versionConfigStream.str().size());
|
||||||
|
if (doc.HasMember("curVersion") && doc["curVersion"].IsString())
|
||||||
|
version = doc["curVersion"].GetString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (const std::exception &e)
|
||||||
|
{
|
||||||
|
std::cerr << e.what() << '\n';
|
||||||
|
}
|
||||||
|
#elif defined(_MAC_PLATFORM_)
|
||||||
|
std::string version = "6.9.19-16183";
|
||||||
|
try
|
||||||
|
{
|
||||||
|
std::ifstream versionConfig("/Applications/QQ.app/Contents/resources/app/package.json");
|
||||||
|
if (versionConfig.is_open())
|
||||||
|
{
|
||||||
|
std::stringstream versionConfigStrBuf;
|
||||||
|
versionConfigStrBuf << versionConfig.rdbuf();
|
||||||
|
versionConfig.close();
|
||||||
|
rapidjson::Document doc;
|
||||||
|
doc.Parse(versionConfigStrBuf.str().c_str(), versionConfigStrBuf.str().size());
|
||||||
|
if (doc.HasMember("version") && doc["version"].IsString())
|
||||||
|
version = doc["version"].GetString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (const std::exception &e)
|
||||||
|
{
|
||||||
|
std::cerr << e.what() << '\n';
|
||||||
|
}
|
||||||
|
#elif defined(_LINUX_PLATFORM_)
|
||||||
|
std::string version = "3.2.9-24815";
|
||||||
|
try
|
||||||
|
{
|
||||||
|
std::ifstream versionConfig("/opt/QQ/resources/app/package.json");
|
||||||
|
if (versionConfig.is_open())
|
||||||
|
{
|
||||||
|
std::stringstream versionConfigStrBuf;
|
||||||
|
versionConfigStrBuf << versionConfig.rdbuf();
|
||||||
|
versionConfig.close();
|
||||||
|
rapidjson::Document doc;
|
||||||
|
doc.Parse(versionConfigStrBuf.str().c_str(), versionConfigStrBuf.str().size());
|
||||||
|
if (doc.HasMember("version") && doc["version"].IsString())
|
||||||
|
version = doc["version"].GetString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (const std::exception &e)
|
||||||
|
{
|
||||||
|
std::cerr << e.what() << '\n';
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
std::string ip = "0.0.0.0";
|
||||||
|
int port = 8080;
|
||||||
|
|
||||||
|
std::string default_config = R"({"ip":"0.0.0.0","port":8080})";
|
||||||
|
|
||||||
|
rapidjson::Document doc;
|
||||||
|
|
||||||
|
std::ifstream configFile("sign.json");
|
||||||
|
if (!configFile.is_open())
|
||||||
|
{
|
||||||
|
printf("sign.json not found, use default\n");
|
||||||
|
std::ofstream("sign.json") << default_config;
|
||||||
|
doc.Parse(default_config.c_str(), default_config.size());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::stringstream configStream;
|
||||||
|
configStream << configFile.rdbuf();
|
||||||
|
configFile.close();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
doc.Parse(configStream.str().c_str(), configStream.str().size());
|
||||||
|
}
|
||||||
|
catch (const std::exception &e)
|
||||||
|
{
|
||||||
|
printf("Parse config failed, use default: %s\n", e.what());
|
||||||
|
doc.Parse(default_config.c_str(), default_config.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (doc.HasMember("ip") && doc["ip"].IsString())
|
||||||
|
ip = doc["ip"].GetString();
|
||||||
|
if (doc.HasMember("port") && doc["port"].IsInt())
|
||||||
|
port = doc["port"].GetInt();
|
||||||
|
if (doc.HasMember("version") && doc["version"].IsString())
|
||||||
|
version = doc["version"].GetString();
|
||||||
|
|
||||||
|
std::thread sign_init([version, ip, port]
|
||||||
|
{
|
||||||
|
printf("Start Init sign\n");
|
||||||
|
for (int i = 0; i < 10; i++)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (Sign::Init(version))
|
||||||
|
{
|
||||||
|
printf("Start Init server\n");
|
||||||
|
Server server;
|
||||||
|
server.Init();
|
||||||
|
if (!server.Run(ip, port))
|
||||||
|
printf("Server run failed\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (const std::exception &e)
|
||||||
|
{
|
||||||
|
printf("Init failed: %s\n", e.what());
|
||||||
|
}
|
||||||
|
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||||
|
} });
|
||||||
|
sign_init.detach();
|
||||||
|
}
|
||||||
|
|
||||||
|
void uninit()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(_WIN_PLATFORM_)
|
||||||
|
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)
|
||||||
|
{
|
||||||
|
switch (fdwReason)
|
||||||
|
{
|
||||||
|
case DLL_PROCESS_ATTACH:
|
||||||
|
init();
|
||||||
|
break;
|
||||||
|
case DLL_THREAD_ATTACH:
|
||||||
|
break;
|
||||||
|
case DLL_THREAD_DETACH:
|
||||||
|
break;
|
||||||
|
case DLL_PROCESS_DETACH:
|
||||||
|
uninit();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
#elif defined(_LINUX_PLATFORM_) || defined(_MAC_PLATFORM_)
|
||||||
|
static void __attribute__((constructor)) my_init(void)
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __attribute__((destructor)) my_fini(void)
|
||||||
|
{
|
||||||
|
uninit();
|
||||||
|
}
|
||||||
|
#endif
|
@ -1,110 +0,0 @@
|
|||||||
#if defined(_MAC_PLATFORM_) || defined(_LINUX_PLATFORM_)
|
|
||||||
|
|
||||||
#include "proc_maps.h"
|
|
||||||
|
|
||||||
hak::proc_maps::proc_maps(uint64_t start, uint64_t end) {
|
|
||||||
this->_start = start;
|
|
||||||
this->_end = end;
|
|
||||||
}
|
|
||||||
|
|
||||||
void hak::proc_maps::insert(std::shared_ptr<hak::proc_maps> maps) { // NOLINT(*-unnecessary-value-param)
|
|
||||||
if (maps == shared_from_this()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (this->_tail == nullptr) {
|
|
||||||
this->_tail = maps;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
auto temp = this->_tail;
|
|
||||||
maps->_head = shared_from_this();
|
|
||||||
maps->last()->_tail = temp;
|
|
||||||
this->_tail = maps;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void hak::proc_maps::remove() {
|
|
||||||
_head->_tail = _tail;
|
|
||||||
_tail->_head = _head;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto hak::proc_maps::size() -> size_t {
|
|
||||||
size_t size = 1;
|
|
||||||
auto curr = shared_from_this();
|
|
||||||
while ((curr = curr->next()) != nullptr) {
|
|
||||||
size++;
|
|
||||||
}
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto hak::proc_maps::start() const -> uint64_t {
|
|
||||||
return _start;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto hak::proc_maps::end() const -> uint64_t {
|
|
||||||
return _end;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto hak::proc_maps::next() -> std::shared_ptr<hak::proc_maps> & {
|
|
||||||
return _tail;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto hak::proc_maps::last() -> std::shared_ptr<hak::proc_maps> {
|
|
||||||
auto curr = shared_from_this();
|
|
||||||
std::shared_ptr<proc_maps> result = curr;
|
|
||||||
while ((curr = curr->next()) != nullptr) {
|
|
||||||
result = curr;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void llex_maps(pid_t pid, const std::function<void(std::shared_ptr<hak::proc_maps>)> &callback) {
|
|
||||||
std::ifstream maps(std::string("/proc/") + (pid == 0 ? std::string("self") : std::to_string(pid)) + "/maps");
|
|
||||||
if (!maps.is_open()) {
|
|
||||||
throw std::exception();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string line;
|
|
||||||
bool last_is_cd = false;
|
|
||||||
while (getline(maps, line)) {
|
|
||||||
std::istringstream iss(line);
|
|
||||||
std::vector<std::string> tokens;
|
|
||||||
std::string token;
|
|
||||||
|
|
||||||
while (getline(iss, token, ' ')) {
|
|
||||||
tokens.push_back(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto address = tokens[0];
|
|
||||||
std::string::size_type pos = address.find('-');
|
|
||||||
uint64_t start_addr = std::stoull(address.substr(0, pos), nullptr, 16);
|
|
||||||
uint64_t end_addr = std::stoull(address.substr(pos + 1), nullptr, 16);
|
|
||||||
auto pmaps = std::make_shared<hak::proc_maps>(start_addr, end_addr);
|
|
||||||
auto perms = tokens[1];
|
|
||||||
pmaps->readable = perms[0] == 'r';
|
|
||||||
pmaps->writable = perms[1] == 'w';
|
|
||||||
pmaps->executable = perms[2] == 'x';
|
|
||||||
pmaps->is_private = perms[3] == 'p';
|
|
||||||
pmaps->offset = std::stoull(tokens[2], nullptr, 16);
|
|
||||||
if (tokens.size() > 5) {
|
|
||||||
for (int i = 5; i < tokens.size(); i++) {
|
|
||||||
pmaps->module_name += tokens[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
callback(pmaps);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto hak::get_maps(pid_t pid) -> std::shared_ptr<proc_maps> {
|
|
||||||
std::shared_ptr<proc_maps> head;
|
|
||||||
llex_maps(pid, [&](std::shared_ptr<proc_maps> maps) { // NOLINT(*-unnecessary-value-param)
|
|
||||||
if (head == nullptr) {
|
|
||||||
head.swap(maps);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
head->insert(maps);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return head;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,49 +0,0 @@
|
|||||||
#ifndef PROC_MAPS_H
|
|
||||||
#define PROC_MAPS_H
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <fstream>
|
|
||||||
#include <sstream>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
#include <functional>
|
|
||||||
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
namespace hak {
|
|
||||||
class proc_maps: public std::enable_shared_from_this<proc_maps> {
|
|
||||||
std::shared_ptr<proc_maps> _head;
|
|
||||||
std::shared_ptr<proc_maps> _tail;
|
|
||||||
|
|
||||||
uint64_t _start;
|
|
||||||
uint64_t _end;
|
|
||||||
public:
|
|
||||||
proc_maps(uint64_t start, uint64_t end);
|
|
||||||
|
|
||||||
bool readable = false;
|
|
||||||
bool writable = false;
|
|
||||||
bool executable = false;
|
|
||||||
bool is_private = false;
|
|
||||||
uint32_t offset = 0;
|
|
||||||
std::string module_name;
|
|
||||||
|
|
||||||
void insert(std::shared_ptr<proc_maps> maps);
|
|
||||||
|
|
||||||
void remove();
|
|
||||||
|
|
||||||
// The speed of this api is not very fast~~~!
|
|
||||||
auto size() -> size_t;
|
|
||||||
|
|
||||||
[[nodiscard]] auto start() const -> uint64_t;
|
|
||||||
|
|
||||||
[[nodiscard]] auto end() const -> uint64_t;
|
|
||||||
|
|
||||||
auto last() -> std::shared_ptr<proc_maps>;
|
|
||||||
|
|
||||||
auto next() -> std::shared_ptr<proc_maps>&;
|
|
||||||
};
|
|
||||||
|
|
||||||
auto get_maps(pid_t pid = 0) -> std::shared_ptr<proc_maps>;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // PROC_MAPS_H
|
|
93
src/run_as_node.cpp
Normal file
93
src/run_as_node.cpp
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
#if defined(_WIN_PLATFORM_)
|
||||||
|
#include "run_as_node.h"
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
|
#include <codecvt>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#if defined(_X64_ARCH_) // {call winmain, check run as node function}
|
||||||
|
std::map<std::string, std::tuple<uint64_t, uint64_t, uint64_t>> mainAddrMap = {
|
||||||
|
{"9.9.12-25234", {0x457A76D, 0x3A5D70, 0x1FFF710}}};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int(__stdcall *oriWinMain)(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd);
|
||||||
|
|
||||||
|
void(__fastcall *checkRunAsNode)(void *a1);
|
||||||
|
|
||||||
|
std::shared_ptr<void> (*nodeInitializeOncePerProcess)(
|
||||||
|
const std::vector<std::string> &args,
|
||||||
|
uint32_t flags);
|
||||||
|
|
||||||
|
int __stdcall fakeWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
|
||||||
|
{
|
||||||
|
checkRunAsNode(nullptr);
|
||||||
|
return oriWinMain(hInstance, hPrevInstance, lpCmdLine, nShowCmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RunAsNode::RunNode()
|
||||||
|
{
|
||||||
|
struct Arguments
|
||||||
|
{
|
||||||
|
int argc = 0;
|
||||||
|
wchar_t **argv =
|
||||||
|
::CommandLineToArgvW(::GetCommandLineW(), &argc);
|
||||||
|
|
||||||
|
~Arguments() { LocalFree(argv); }
|
||||||
|
} arguments;
|
||||||
|
|
||||||
|
std::vector<std::string> argv(arguments.argc);
|
||||||
|
|
||||||
|
std::transform(arguments.argv, arguments.argv + arguments.argc, argv.begin(),
|
||||||
|
[](auto &a)
|
||||||
|
{ return std::wstring_convert<std::codecvt_utf8<wchar_t>>().to_bytes(a); });
|
||||||
|
|
||||||
|
nodeInitializeOncePerProcess(argv, (1 << 6) | (1 << 7));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RunAsNode::Init(const std::string &version)
|
||||||
|
{
|
||||||
|
uint64_t baseAddr = 0;
|
||||||
|
#if defined(_WIN_PLATFORM_)
|
||||||
|
HMODULE wrapperModule = GetModuleHandleW(NULL);
|
||||||
|
if (wrapperModule == NULL)
|
||||||
|
throw std::runtime_error("Can't GetModuleHandle");
|
||||||
|
baseAddr = reinterpret_cast<uint64_t>(wrapperModule);
|
||||||
|
printf("baseAddr: %llx\n", baseAddr);
|
||||||
|
#elif defined(_MAC_PLATFORM_)
|
||||||
|
auto pmap = hak::get_maps();
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (pmap->module_name.find("QQ") != std::string::npos && pmap->offset == 0)
|
||||||
|
{
|
||||||
|
baseAddr = pmap->start();
|
||||||
|
printf("baseAddr: %llx\n", baseAddr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while ((pmap = pmap->next()) != nullptr);
|
||||||
|
#elif defined(_LINUX_PLATFORM_)
|
||||||
|
auto pmap = hak::get_maps();
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (pmap->module_name.find("QQ") != std::string::npos && pmap->offset == 0)
|
||||||
|
{
|
||||||
|
baseAddr = pmap->start();
|
||||||
|
printf("baseAddr: %lx\n", baseAddr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while ((pmap = pmap->next()) != nullptr);
|
||||||
|
#endif
|
||||||
|
if (baseAddr == 0)
|
||||||
|
throw std::runtime_error("Can't find hook address");
|
||||||
|
|
||||||
|
auto [callptr, func1ptr, func2ptr] = mainAddrMap[version];
|
||||||
|
|
||||||
|
uint8_t *abscallptr = reinterpret_cast<uint8_t *>(baseAddr + callptr);
|
||||||
|
oriWinMain = reinterpret_cast<int(__stdcall *)(HINSTANCE, HINSTANCE, LPSTR, int)>(moehoo::get_call_address(abscallptr));
|
||||||
|
checkRunAsNode = reinterpret_cast<void(__fastcall *)(void *)>(baseAddr + func1ptr);
|
||||||
|
nodeInitializeOncePerProcess = reinterpret_cast<std::shared_ptr<void> (*)(const std::vector<std::string> &, uint32_t)>(baseAddr + func2ptr);
|
||||||
|
return moehoo::hook(abscallptr, &fakeWinMain);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
9
src/run_as_node.h
Normal file
9
src/run_as_node.h
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../include/moehoo/hook.h"
|
||||||
|
|
||||||
|
namespace RunAsNode
|
||||||
|
{
|
||||||
|
bool Init(const std::string &version);
|
||||||
|
bool RunNode();
|
||||||
|
}
|
127
src/server.cpp
127
src/server.cpp
@ -2,9 +2,11 @@
|
|||||||
#include "../include/rapidjson/document.h"
|
#include "../include/rapidjson/document.h"
|
||||||
#include "../include/rapidjson/writer.h"
|
#include "../include/rapidjson/writer.h"
|
||||||
|
|
||||||
#include <thread>
|
std::string Server::GetSign(const std::string_view &cmd, const std::string_view &src, const int seq)
|
||||||
|
{
|
||||||
|
auto [signDataHex, extraDataHex, tokenDataHex] = Sign::Call(cmd, src, seq);
|
||||||
|
counter++;
|
||||||
|
|
||||||
std::string ConstructResponse(const std::string &sign, const std::string &extra, const std::string &token) {
|
|
||||||
rapidjson::StringBuffer buffer;
|
rapidjson::StringBuffer buffer;
|
||||||
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
|
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
|
||||||
|
|
||||||
@ -12,86 +14,77 @@ std::string ConstructResponse(const std::string &sign, const std::string &extra,
|
|||||||
writer.Key("value");
|
writer.Key("value");
|
||||||
writer.StartObject();
|
writer.StartObject();
|
||||||
writer.Key("sign");
|
writer.Key("sign");
|
||||||
writer.String(sign.c_str());
|
writer.String(signDataHex.c_str());
|
||||||
writer.Key("extra");
|
writer.Key("extra");
|
||||||
writer.String(extra.c_str());
|
writer.String(extraDataHex.c_str());
|
||||||
writer.Key("token");
|
writer.Key("token");
|
||||||
writer.String(token.c_str());
|
writer.String(tokenDataHex.c_str());
|
||||||
writer.EndObject();
|
writer.EndObject();
|
||||||
writer.EndObject();
|
writer.EndObject();
|
||||||
|
|
||||||
return buffer.GetString();
|
return buffer.GetString();
|
||||||
}
|
}
|
||||||
|
|
||||||
Server::Server(int port) {
|
void Server::Init()
|
||||||
std::atomic<uint64_t> counter(0);
|
{
|
||||||
|
svr.Post("/sign", [this](const httplib::Request &req, httplib::Response &res)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
rapidjson::Document doc;
|
||||||
|
doc.Parse(req.body.c_str(), req.body.size());
|
||||||
|
|
||||||
svr.Post("/sign", [this, &counter](const httplib::Request &req, httplib::Response &res)
|
std::string_view cmd = doc["cmd"].GetString();
|
||||||
{
|
std::string_view src = doc["src"].GetString();
|
||||||
try {
|
int seq = doc["seq"].GetInt();
|
||||||
rapidjson::Document doc;
|
|
||||||
doc.Parse(req.body.c_str(), req.body.size());
|
|
||||||
|
|
||||||
std::string_view cmd = doc["cmd"].GetString();
|
std::string buffer = GetSign(cmd, src, seq);
|
||||||
std::string_view src = doc["src"].GetString();
|
|
||||||
int seq = doc["seq"].GetInt();
|
|
||||||
|
|
||||||
auto [signDataHex, extraDataHex, tokenDataHex] = sign.Call(cmd, src, seq);
|
res.set_content(buffer, "application/json");
|
||||||
std::string buffer = ConstructResponse(signDataHex, extraDataHex, tokenDataHex);
|
}
|
||||||
counter++;
|
catch (...) {
|
||||||
|
res.set_content("Bad Request", "text/plain");
|
||||||
|
res.status = httplib::StatusCode::BadRequest_400;
|
||||||
|
} })
|
||||||
|
.Get("/sign", [this](const httplib::Request &req, httplib::Response &res)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
std::string cmd = req.get_param_value("cmd");
|
||||||
|
std::string src = req.get_param_value("src");
|
||||||
|
int seq = std::stoi(req.get_param_value("seq"));
|
||||||
|
|
||||||
res.set_content(buffer, "application/json");
|
std::string buffer = GetSign(cmd, src, seq);
|
||||||
}
|
|
||||||
catch (...) {
|
|
||||||
res.set_content("Bad Request", "text/plain");
|
|
||||||
res.status = httplib::StatusCode::BadRequest_400;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
svr.Get("/sign", [this, &counter](const httplib::Request &req, httplib::Response &res)
|
res.set_content(buffer, "application/json");
|
||||||
{
|
}
|
||||||
try {
|
catch (...) {
|
||||||
std::string cmd = req.get_param_value("cmd");
|
res.set_content("Bad Request", "text/plain");
|
||||||
std::string src = req.get_param_value("src");
|
res.status = httplib::StatusCode::BadRequest_400;
|
||||||
int seq = std::stoi(req.get_param_value("seq"));
|
} })
|
||||||
|
.Get("/ping", [](const httplib::Request &req, httplib::Response &res)
|
||||||
|
{
|
||||||
|
rapidjson::StringBuffer buffer;
|
||||||
|
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
|
||||||
|
|
||||||
auto [signDataHex, extraDataHex, tokenDataHex] = sign.Call(cmd, src, seq);
|
writer.StartObject();
|
||||||
std::string buffer = ConstructResponse(signDataHex, extraDataHex, tokenDataHex);
|
writer.Key("code");
|
||||||
counter++;
|
writer.Int(0);
|
||||||
|
writer.EndObject();
|
||||||
|
|
||||||
res.set_content(buffer, "application/json");
|
res.set_content(buffer.GetString(), "application/json"); })
|
||||||
}
|
.Get("/count", [this](const httplib::Request &req, httplib::Response &res)
|
||||||
catch (...) {
|
{
|
||||||
res.set_content("Bad Request", "text/plain");
|
rapidjson::StringBuffer buffer;
|
||||||
res.status = httplib::StatusCode::BadRequest_400;
|
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
svr.Get("/ping", [](const httplib::Request &req, httplib::Response &res)
|
writer.StartObject();
|
||||||
{
|
writer.Key("count");
|
||||||
rapidjson::StringBuffer buffer;
|
writer.String(std::to_string(counter.load()).c_str());
|
||||||
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
|
writer.EndObject();
|
||||||
|
|
||||||
writer.StartObject();
|
res.set_content(buffer.GetString(), "application/json"); });
|
||||||
writer.Key("code");
|
}
|
||||||
writer.Int(0);
|
|
||||||
writer.EndObject();
|
|
||||||
|
|
||||||
res.set_content(buffer.GetString(), "application/json");
|
bool Server::Run(const std::string &ip, int port)
|
||||||
});
|
{
|
||||||
|
return svr.listen(ip.c_str(), port);
|
||||||
svr.Get("/count", [&counter](const httplib::Request &req, httplib::Response &res)
|
}
|
||||||
{
|
|
||||||
rapidjson::StringBuffer buffer;
|
|
||||||
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
|
|
||||||
|
|
||||||
writer.StartObject();
|
|
||||||
writer.Key("count");
|
|
||||||
writer.String(std::to_string(counter.load()).c_str());
|
|
||||||
writer.EndObject();
|
|
||||||
|
|
||||||
res.set_content(buffer.GetString(), "application/json");
|
|
||||||
});
|
|
||||||
|
|
||||||
std::thread([this, port]{ svr.listen("0.0.0.0", port); }).detach();
|
|
||||||
}
|
|
||||||
|
15
src/server.h
15
src/server.h
@ -1,12 +1,19 @@
|
|||||||
|
#pragma once
|
||||||
|
#define _DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR
|
||||||
|
|
||||||
#include "sign.h"
|
#include "sign.h"
|
||||||
#include "../include/cpp-httplib/httplib.h"
|
#include "../include/cpp-httplib/httplib.h"
|
||||||
|
|
||||||
class Server
|
class Server
|
||||||
{
|
{
|
||||||
public:
|
|
||||||
Server(int port);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
httplib::Server svr;
|
httplib::Server svr;
|
||||||
Sign sign;
|
std::atomic<uint64_t> counter = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string GetSign(const std::string_view &cmd, const std::string_view &src, const int seq);
|
||||||
|
|
||||||
|
public:
|
||||||
|
void Init();
|
||||||
|
bool Run(const std::string &ip, int port);
|
||||||
};
|
};
|
143
src/sign.cpp
143
src/sign.cpp
@ -1,72 +1,70 @@
|
|||||||
#include "sign.h"
|
#include "sign.h"
|
||||||
|
|
||||||
#include <mutex>
|
|
||||||
#include <sstream>
|
|
||||||
#include <iostream>
|
|
||||||
#include <vector>
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
#include <stdexcept>
|
||||||
// #define _LINUX_PLATFORM_
|
|
||||||
// #define _WIN_PLATFORM_
|
|
||||||
|
|
||||||
// #define _X64_ARCH_
|
|
||||||
|
|
||||||
#if defined(_WIN_PLATFORM_)
|
#if defined(_WIN_PLATFORM_)
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
#include <psapi.h>
|
#elif defined(_LINUX_PLATFORM_) || defined(_MAC_PLATFORM_)
|
||||||
#elif defined(_MAC_PLATFORM_) || defined(_LINUX_PLATFORM_)
|
#include "../include/moehoo/proc_maps.h"
|
||||||
#include "proc_maps.h"
|
|
||||||
#include <cstring>
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
typedef int (*SignFunctionType)(const char *cmd, const unsigned char *src, size_t src_len, int seq, unsigned char *result);
|
||||||
|
SignFunctionType SignFunction = nullptr;
|
||||||
|
|
||||||
// 签名函数定义
|
// 签名函数定义
|
||||||
#if defined(_WIN_PLATFORM_)
|
|
||||||
#define CURRENT_VERSION "9.9.9-23361"
|
|
||||||
#if defined(_X64_ARCH_)
|
#if defined(_X64_ARCH_)
|
||||||
std::map<std::string, uint64_t> addrMap = {
|
std::map<std::string, uint64_t> addrMap = {
|
||||||
|
// Linux
|
||||||
|
{"3.1.2-12912", 0x33C38E0},
|
||||||
|
{"3.1.2-13107", 0x33C3920},
|
||||||
|
{"3.2.7-23361", 0x4C93C57},
|
||||||
|
{"3.2.9-24815", 0x4E5D3B7},
|
||||||
|
{"3.2.10-25765", 0x4F176D6},
|
||||||
|
// Macos
|
||||||
|
{"6.9.19-16183", 0x1B29469},
|
||||||
|
// Windows
|
||||||
{"9.9.2-16183", 0x2E0D0},
|
{"9.9.2-16183", 0x2E0D0},
|
||||||
{"9.9.9-23361", 0x2EB50},
|
{"9.9.9-23361", 0x2EB50},
|
||||||
{"9.9.9-23424", 0x2EB50}};
|
{"9.9.9-23424", 0x2EB50},
|
||||||
|
{"9.9.9-23424", 0x2EB50},
|
||||||
|
{"9.9.10-24108", 0x2EB50},
|
||||||
|
{"9.9.11-24568", 0xAA1A20},
|
||||||
|
{"9.9.11-24815", 0xAB5510},
|
||||||
|
{"9.9.12-25234", 0xA84980},
|
||||||
|
{"9.9.12-25300", 0xA84980},
|
||||||
|
{"9.9.12-25493", 0xA996E0},
|
||||||
|
{"9.9.12-25765", 0xA9CE90},
|
||||||
|
{"9.9.12-26299", 0xA9E5B0},
|
||||||
|
{"9.9.12-26299", 0xA9E5B0},
|
||||||
|
{"9.9.15-27597", 0xBDAE40}};
|
||||||
#elif defined(_X86_ARCH_)
|
#elif defined(_X86_ARCH_)
|
||||||
std::map<std::string, uint64_t> addrMap = {
|
std::map<std::string, uint64_t> addrMap = {
|
||||||
{"9.9.2-15962", 0x2BD70},
|
{"9.9.2-15962", 0x2BD70},
|
||||||
{"9.9.2-16183", 0x2BD70}};
|
{"9.9.2-16183", 0x2BD70}};
|
||||||
#endif
|
|
||||||
#elif defined(_MAC_PLATFORM_)
|
|
||||||
#define CURRENT_VERSION "6.9.20-17153"
|
|
||||||
#if defined(_X64_ARCH_)
|
|
||||||
std::map<std::string, uint64_t> addrMap = {
|
|
||||||
{"6.9.19-16183", 0x1B29469}};
|
|
||||||
#elif defined(_ARM64_ARCH_)
|
#elif defined(_ARM64_ARCH_)
|
||||||
std::map<std::string, uint64_t> addrMap = {
|
std::map<std::string, uint64_t> addrMap = {
|
||||||
{"6.9.20-17153", 0x1c73dd0}};
|
{"3.2.7-23361", 0x351EC98},
|
||||||
#endif
|
{"6.9.20-17153", 0x1c73dd0},
|
||||||
#elif defined(_LINUX_PLATFORM_)
|
{"6.9.56-28418", 0x23510E8}};
|
||||||
#define CURRENT_VERSION "3.2.7-23361"
|
|
||||||
#if defined(_X64_ARCH_)
|
|
||||||
std::map<std::string, uint64_t> addrMap = {
|
|
||||||
{"3.1.2-12912", 0x33C38E0},
|
|
||||||
{"3.1.2-13107", 0x33C3920},
|
|
||||||
{"3.2.7-23361", 0x4C93C57}};
|
|
||||||
#elif defined(_ARM64_ARCH_)
|
|
||||||
std::map<std::string, uint64_t> addrMap = {
|
|
||||||
{"3.2.7-23361", 0x4C93C57}};
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int SignOffsets = 767; // 562 before 3.1.2-13107, 767 in others
|
int SignOffsets = 767; // 562 before 3.1.2-13107, 767 in others
|
||||||
int ExtraOffsets = 511;
|
int ExtraOffsets = 511;
|
||||||
int TokenOffsets = 255;
|
int TokenOffsets = 255;
|
||||||
|
|
||||||
std::vector<uint8_t> Hex2Bin(std::string_view str) {
|
std::vector<uint8_t> Hex2Bin(std::string_view str)
|
||||||
if (str.length() % 2 != 0) {
|
{
|
||||||
throw std::invalid_argument("Hex string length must be even");
|
if (str.length() % 2 != 0)
|
||||||
}
|
{
|
||||||
|
throw std::invalid_argument("Hex string length must be even");
|
||||||
|
}
|
||||||
std::vector<uint8_t> bin(str.size() / 2);
|
std::vector<uint8_t> bin(str.size() / 2);
|
||||||
std::string extract("00");
|
std::string extract("00");
|
||||||
for (size_t i = 0; i < str.size() / 2; i++) {
|
for (size_t i = 0; i < str.size() / 2; i++)
|
||||||
|
{
|
||||||
extract[0] = str[2 * i];
|
extract[0] = str[2 * i];
|
||||||
extract[1] = str[2 * i + 1];
|
extract[1] = str[2 * i + 1];
|
||||||
bin[i] = std::stoi(extract, nullptr, 16);
|
bin[i] = std::stoi(extract, nullptr, 16);
|
||||||
@ -74,73 +72,66 @@ std::vector<uint8_t> Hex2Bin(std::string_view str) {
|
|||||||
return bin;
|
return bin;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Bin2Hex(const uint8_t *ptr, size_t length) {
|
std::string Bin2Hex(const uint8_t *ptr, size_t length)
|
||||||
|
{
|
||||||
const char table[] = "0123456789ABCDEF";
|
const char table[] = "0123456789ABCDEF";
|
||||||
std::string str;
|
std::string str;
|
||||||
str.resize(length * 2);
|
str.resize(length * 2);
|
||||||
for (size_t i = 0; i < length; ++i) {
|
for (size_t i = 0; i < length; ++i)
|
||||||
|
{
|
||||||
str[2 * i] = table[ptr[i] / 16];
|
str[2 * i] = table[ptr[i] / 16];
|
||||||
str[2 * i + 1] = table[ptr[i] % 16];
|
str[2 * i + 1] = table[ptr[i] % 16];
|
||||||
}
|
}
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
Sign::Sign() {
|
bool Sign::Init(const std::string &version)
|
||||||
std::thread([this]{ while (false) {
|
{
|
||||||
try {
|
|
||||||
Init();
|
|
||||||
}
|
|
||||||
catch (const std::exception &e) {
|
|
||||||
std::cerr << e.what() << '\n';
|
|
||||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
} }).detach();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Sign::Init() {
|
|
||||||
uint64_t HookAddress = 0;
|
uint64_t HookAddress = 0;
|
||||||
#if defined(_WIN_PLATFORM_)
|
#if defined(_WIN_PLATFORM_)
|
||||||
HMODULE wrapperModule = GetModuleHandleW(L"wrapper.node");
|
HMODULE wrapperModule = GetModuleHandleW(L"wrapper.node");
|
||||||
if (wrapperModule == NULL) {
|
if (wrapperModule == NULL)
|
||||||
throw std::runtime_error("Can't find wrapper.node module");
|
throw std::runtime_error("Can't find wrapper.node module");
|
||||||
}
|
HookAddress = reinterpret_cast<uint64_t>(wrapperModule) + addrMap[version];
|
||||||
HookAddress = reinterpret_cast<uint64_t>(wrapperModule) + addrMap[CURRENT_VERSION];
|
|
||||||
printf("HookAddress: %llx\n", HookAddress);
|
printf("HookAddress: %llx\n", HookAddress);
|
||||||
#elif defined(_MAC_PLATFORM_)
|
#elif defined(_MAC_PLATFORM_)
|
||||||
auto pmap = hak::get_maps();
|
auto pmap = hak::get_maps();
|
||||||
do {
|
do
|
||||||
if (pmap->module_name.find("wrapper.node") != std::string::npos && pmap->offset == 0) {
|
{
|
||||||
HookAddress = pmap->start() + addrMap[CURRENT_VERSION];
|
if (pmap->module_name.find("wrapper.node") != std::string::npos && pmap->offset == 0)
|
||||||
|
{
|
||||||
|
HookAddress = pmap->start() + addrMap[version];
|
||||||
printf("HookAddress: %llx\n", HookAddress);
|
printf("HookAddress: %llx\n", HookAddress);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} while ((pmap = pmap->next()) != nullptr);
|
} while ((pmap = pmap->next()) != nullptr);
|
||||||
#elif defined(_LINUX_PLATFORM_)
|
#elif defined(_LINUX_PLATFORM_)
|
||||||
auto pmap = hak::get_maps();
|
auto pmap = hak::get_maps();
|
||||||
do {
|
do
|
||||||
if (pmap->module_name.find("wrapper.node") != std::string::npos && pmap->offset == 0) {
|
{
|
||||||
HookAddress = pmap->start() + addrMap[CURRENT_VERSION];
|
if (pmap->module_name.find("wrapper.node") != std::string::npos && pmap->offset == 0)
|
||||||
|
{
|
||||||
|
HookAddress = pmap->start() + addrMap[version];
|
||||||
printf("HookAddress: %lx\n", HookAddress);
|
printf("HookAddress: %lx\n", HookAddress);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} while ((pmap = pmap->next()) != nullptr);
|
} while ((pmap = pmap->next()) != nullptr);
|
||||||
#endif
|
#endif
|
||||||
if (HookAddress == 0) {
|
if (HookAddress == 0)
|
||||||
throw std::runtime_error("Can't find hook address");
|
throw std::runtime_error("Can't find hook address");
|
||||||
}
|
|
||||||
SignFunction = reinterpret_cast<SignFunctionType>(HookAddress);
|
SignFunction = reinterpret_cast<SignFunctionType>(HookAddress);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::tuple<std::string, std::string, std::string> Sign::Call(const std::string_view cmd, const std::string_view src, int seq) {
|
std::tuple<std::string, std::string, std::string> Sign::Call(const std::string_view cmd, const std::string_view src, int seq)
|
||||||
if (SignFunction == nullptr) {
|
{
|
||||||
throw std::runtime_error("Sign function not initialized");
|
if (SignFunction == nullptr)
|
||||||
}
|
throw std::runtime_error("Sign function not initialized");
|
||||||
|
|
||||||
const std::vector<uint8_t> signArgSrc = Hex2Bin(src);
|
const std::vector<uint8_t> signArgSrc = Hex2Bin(src);
|
||||||
|
|
||||||
size_t resultSize = 1024;
|
size_t resultSize = 1024;
|
||||||
auto *signResult = new uint8_t[resultSize];
|
uint8_t *signResult = new uint8_t[resultSize];
|
||||||
|
|
||||||
SignFunction(cmd.data(), signArgSrc.data(), signArgSrc.size(), seq, signResult);
|
SignFunction(cmd.data(), signArgSrc.data(), signArgSrc.size(), seq, signResult);
|
||||||
|
|
||||||
@ -151,4 +142,4 @@ std::tuple<std::string, std::string, std::string> Sign::Call(const std::string_v
|
|||||||
delete[] signResult;
|
delete[] signResult;
|
||||||
|
|
||||||
return std::make_tuple(signDataHex, extraDataHex, tokenDataHex);
|
return std::make_tuple(signDataHex, extraDataHex, tokenDataHex);
|
||||||
}
|
}
|
||||||
|
16
src/sign.h
16
src/sign.h
@ -1,16 +1,10 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
|
||||||
class Sign
|
namespace Sign
|
||||||
{
|
{
|
||||||
public:
|
bool Init(const std::string &version);
|
||||||
Sign();
|
|
||||||
|
|
||||||
private:
|
|
||||||
typedef int (*SignFunctionType)(const char *cmd, const unsigned char *src, size_t src_len, int seq, unsigned char *result);
|
|
||||||
SignFunctionType SignFunction = nullptr;
|
|
||||||
void Init();
|
|
||||||
|
|
||||||
public:
|
|
||||||
std::tuple<std::string, std::string, std::string> Call(const std::string_view cmd, const std::string_view src, int seq);
|
std::tuple<std::string, std::string, std::string> Call(const std::string_view cmd, const std::string_view src, int seq);
|
||||||
};
|
}
|
114
src/version.asm
114
src/version.asm
@ -1,114 +0,0 @@
|
|||||||
ifdef _WIN_PLATFORM_
|
|
||||||
ifdef RAX
|
|
||||||
.code
|
|
||||||
extern OriginalFuncs_version:QWORD
|
|
||||||
GetFileVersionInfoA proc
|
|
||||||
jmp QWORD ptr OriginalFuncs_version[0 * 8]
|
|
||||||
GetFileVersionInfoA endp
|
|
||||||
GetFileVersionInfoByHandle proc
|
|
||||||
jmp QWORD ptr OriginalFuncs_version[1 * 8]
|
|
||||||
GetFileVersionInfoByHandle endp
|
|
||||||
GetFileVersionInfoExA proc
|
|
||||||
jmp QWORD ptr OriginalFuncs_version[2 * 8]
|
|
||||||
GetFileVersionInfoExA endp
|
|
||||||
GetFileVersionInfoExW proc
|
|
||||||
jmp QWORD ptr OriginalFuncs_version[3 * 8]
|
|
||||||
GetFileVersionInfoExW endp
|
|
||||||
GetFileVersionInfoSizeA proc
|
|
||||||
jmp QWORD ptr OriginalFuncs_version[4 * 8]
|
|
||||||
GetFileVersionInfoSizeA endp
|
|
||||||
GetFileVersionInfoSizeExA proc
|
|
||||||
jmp QWORD ptr OriginalFuncs_version[5 * 8]
|
|
||||||
GetFileVersionInfoSizeExA endp
|
|
||||||
GetFileVersionInfoSizeExW proc
|
|
||||||
jmp QWORD ptr OriginalFuncs_version[6 * 8]
|
|
||||||
GetFileVersionInfoSizeExW endp
|
|
||||||
GetFileVersionInfoSizeW proc
|
|
||||||
jmp QWORD ptr OriginalFuncs_version[7 * 8]
|
|
||||||
GetFileVersionInfoSizeW endp
|
|
||||||
GetFileVersionInfoW proc
|
|
||||||
jmp QWORD ptr OriginalFuncs_version[8 * 8]
|
|
||||||
GetFileVersionInfoW endp
|
|
||||||
VerFindFileA proc
|
|
||||||
jmp QWORD ptr OriginalFuncs_version[9 * 8]
|
|
||||||
VerFindFileA endp
|
|
||||||
VerFindFileW proc
|
|
||||||
jmp QWORD ptr OriginalFuncs_version[10 * 8]
|
|
||||||
VerFindFileW endp
|
|
||||||
VerInstallFileA proc
|
|
||||||
jmp QWORD ptr OriginalFuncs_version[11 * 8]
|
|
||||||
VerInstallFileA endp
|
|
||||||
VerInstallFileW proc
|
|
||||||
jmp QWORD ptr OriginalFuncs_version[12 * 8]
|
|
||||||
VerInstallFileW endp
|
|
||||||
VerLanguageNameA proc
|
|
||||||
jmp QWORD ptr OriginalFuncs_version[13 * 8]
|
|
||||||
VerLanguageNameA endp
|
|
||||||
VerLanguageNameW proc
|
|
||||||
jmp QWORD ptr OriginalFuncs_version[14 * 8]
|
|
||||||
VerLanguageNameW endp
|
|
||||||
VerQueryValueA proc
|
|
||||||
jmp QWORD ptr OriginalFuncs_version[15 * 8]
|
|
||||||
VerQueryValueA endp
|
|
||||||
VerQueryValueW proc
|
|
||||||
jmp QWORD ptr OriginalFuncs_version[16 * 8]
|
|
||||||
VerQueryValueW endp
|
|
||||||
else
|
|
||||||
.model flat, C
|
|
||||||
.stack 4096
|
|
||||||
.code
|
|
||||||
extern OriginalFuncs_version:DWORD
|
|
||||||
GetFileVersionInfoA proc
|
|
||||||
jmp DWORD ptr OriginalFuncs_version[0 * 4]
|
|
||||||
GetFileVersionInfoA endp
|
|
||||||
GetFileVersionInfoByHandle proc
|
|
||||||
jmp DWORD ptr OriginalFuncs_version[1 * 4]
|
|
||||||
GetFileVersionInfoByHandle endp
|
|
||||||
GetFileVersionInfoExA proc
|
|
||||||
jmp DWORD ptr OriginalFuncs_version[2 * 4]
|
|
||||||
GetFileVersionInfoExA endp
|
|
||||||
GetFileVersionInfoExW proc
|
|
||||||
jmp DWORD ptr OriginalFuncs_version[3 * 4]
|
|
||||||
GetFileVersionInfoExW endp
|
|
||||||
GetFileVersionInfoSizeA proc
|
|
||||||
jmp DWORD ptr OriginalFuncs_version[4 * 4]
|
|
||||||
GetFileVersionInfoSizeA endp
|
|
||||||
GetFileVersionInfoSizeExA proc
|
|
||||||
jmp DWORD ptr OriginalFuncs_version[5 * 4]
|
|
||||||
GetFileVersionInfoSizeExA endp
|
|
||||||
GetFileVersionInfoSizeExW proc
|
|
||||||
jmp DWORD ptr OriginalFuncs_version[6 * 4]
|
|
||||||
GetFileVersionInfoSizeExW endp
|
|
||||||
GetFileVersionInfoSizeW proc
|
|
||||||
jmp DWORD ptr OriginalFuncs_version[7 * 4]
|
|
||||||
GetFileVersionInfoSizeW endp
|
|
||||||
GetFileVersionInfoW proc
|
|
||||||
jmp DWORD ptr OriginalFuncs_version[8 * 4]
|
|
||||||
GetFileVersionInfoW endp
|
|
||||||
VerFindFileA proc
|
|
||||||
jmp DWORD ptr OriginalFuncs_version[9 * 4]
|
|
||||||
VerFindFileA endp
|
|
||||||
VerFindFileW proc
|
|
||||||
jmp DWORD ptr OriginalFuncs_version[10 * 4]
|
|
||||||
VerFindFileW endp
|
|
||||||
VerInstallFileA proc
|
|
||||||
jmp DWORD ptr OriginalFuncs_version[11 * 4]
|
|
||||||
VerInstallFileA endp
|
|
||||||
VerInstallFileW proc
|
|
||||||
jmp DWORD ptr OriginalFuncs_version[12 * 4]
|
|
||||||
VerInstallFileW endp
|
|
||||||
VerLanguageNameA proc
|
|
||||||
jmp DWORD ptr OriginalFuncs_version[13 * 4]
|
|
||||||
VerLanguageNameA endp
|
|
||||||
VerLanguageNameW proc
|
|
||||||
jmp DWORD ptr OriginalFuncs_version[14 * 4]
|
|
||||||
VerLanguageNameW endp
|
|
||||||
VerQueryValueA proc
|
|
||||||
jmp DWORD ptr OriginalFuncs_version[15 * 4]
|
|
||||||
VerQueryValueA endp
|
|
||||||
VerQueryValueW proc
|
|
||||||
jmp DWORD ptr OriginalFuncs_version[16 * 4]
|
|
||||||
VerQueryValueW endp
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
end
|
|
32
start.bat
32
start.bat
@ -5,22 +5,46 @@ for /f "tokens=2*" %%a in ('reg query "HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\M
|
|||||||
set "RetString=%%b"
|
set "RetString=%%b"
|
||||||
goto :boot
|
goto :boot
|
||||||
)
|
)
|
||||||
|
echo QQ installation not found
|
||||||
|
pause
|
||||||
|
exit
|
||||||
|
|
||||||
:boot
|
:boot
|
||||||
for %%a in ("!RetString!") do (
|
for %%a in ("!RetString!") do (
|
||||||
set "pathWithoutUninstall=%%~dpa"
|
set "pathWithoutUninstall=%%~dpa"
|
||||||
)
|
)
|
||||||
|
|
||||||
if not exist %pathWithoutUninstall%version.dll (
|
if not exist "%pathWithoutUninstall%dbghelp.dll" (
|
||||||
if not exist %~dp0SignerServer.dll (
|
if not exist %~dp0SignerServer.dll (
|
||||||
echo SignerServer.dll not found
|
echo SignerServer.dll not found
|
||||||
|
pause
|
||||||
exit
|
exit
|
||||||
)
|
)
|
||||||
copy /y "%~dp0SignerServer.dll" "%pathWithoutUninstall%version.dll" 1>NUL 2>NUL || powershell Start-Process -FilePath cmd.exe -ArgumentList """/c pushd %~dp0 && %~s0 %*""" -Verb RunAs && exit
|
goto copydll
|
||||||
|
) else (
|
||||||
|
set /p Choice="dbghelp.dll already exists, do you want to replace it?(Y/N):"
|
||||||
|
if /i "!Choice!"=="Y" goto copydll
|
||||||
|
if /i "!Choice!"=="y" goto copydll
|
||||||
|
goto launch
|
||||||
)
|
)
|
||||||
|
|
||||||
|
:copydll
|
||||||
|
copy /y "%~dp0SignerServer.dll" "%pathWithoutUninstall%dbghelp.dll"
|
||||||
|
if errorlevel 1 (
|
||||||
|
set /p Choice="Copy error, do you want to attempt to running as administrator?(Y/N):"
|
||||||
|
if /i "!Choice!"=="Y" goto restart
|
||||||
|
if /i "!Choice!"=="y" goto restart
|
||||||
|
exit
|
||||||
|
)
|
||||||
|
goto launch
|
||||||
|
|
||||||
|
:restart
|
||||||
|
powershell Start-Process -FilePath cmd.exe -ArgumentList """/c pushd %~dp0 && %~s0 %*""" -Verb RunAs
|
||||||
|
exit
|
||||||
|
|
||||||
|
:launch
|
||||||
set "QQPath=!pathWithoutUninstall!QQ.exe"
|
set "QQPath=!pathWithoutUninstall!QQ.exe"
|
||||||
set ELECTRON_RUN_AS_NODE=1
|
set ELECTRON_RUN_AS_NODE=1
|
||||||
echo !QQPath!
|
|
||||||
|
|
||||||
"!QQPath!" %~dp0load.js %*
|
echo Launching QQ
|
||||||
|
"!QQPath!" "%~dp0load.js" %*
|
4
start.command
Executable file
4
start.command
Executable file
@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
SCRIPT_DIR=$(realpath $(dirname "${BASH_SOURCE[0]}"))
|
||||||
|
export ELECTRON_RUN_AS_NODE=1
|
||||||
|
DYLD_INSERT_LIBRARIES=./libSignerServer.dylib /Applications/QQ.app/Contents/MacOS/qq ${SCRIPT_DIR}/load.js $@
|
18
version.def
18
version.def
@ -1,18 +0,0 @@
|
|||||||
EXPORTS
|
|
||||||
GetFileVersionInfoA
|
|
||||||
GetFileVersionInfoByHandle
|
|
||||||
GetFileVersionInfoExA
|
|
||||||
GetFileVersionInfoExW
|
|
||||||
GetFileVersionInfoSizeA
|
|
||||||
GetFileVersionInfoSizeExA
|
|
||||||
GetFileVersionInfoSizeExW
|
|
||||||
GetFileVersionInfoSizeW
|
|
||||||
GetFileVersionInfoW
|
|
||||||
VerFindFileA
|
|
||||||
VerFindFileW
|
|
||||||
VerInstallFileA
|
|
||||||
VerInstallFileW
|
|
||||||
VerLanguageNameA
|
|
||||||
VerLanguageNameW
|
|
||||||
VerQueryValueA
|
|
||||||
VerQueryValueW
|
|
Loading…
x
Reference in New Issue
Block a user