mirror of
https://github.com/HolographicHat/Yae.git
synced 2025-12-10 16:38:13 +08:00
Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2210a97d61 | ||
|
|
feb7ac44da | ||
|
|
3924129560 | ||
|
|
4f7f0cdfd2 | ||
|
|
cf0753c676 | ||
|
|
0b895d47ca | ||
|
|
78d2722e20 | ||
|
|
385c673323 | ||
|
|
50beb2cce7 | ||
|
|
324a4153e0 | ||
|
|
3de459aceb | ||
|
|
295bb89177 | ||
|
|
baaf4e8227 | ||
|
|
f41fe6fb12 | ||
|
|
78bda3f49c | ||
|
|
a10dc22461 | ||
|
|
74dda750ef | ||
|
|
099270ad29 | ||
|
|
fe5b2c0c12 | ||
|
|
ed5d99745c | ||
|
|
7175cd7427 | ||
|
|
73747bcce5 | ||
|
|
b12c3209d7 | ||
|
|
5805070627 | ||
|
|
811daba164 |
2
.github/workflows/dotnet.yml
vendored
2
.github/workflows/dotnet.yml
vendored
@@ -20,7 +20,7 @@ jobs:
|
||||
- name: Restore dependencies
|
||||
run: dotnet restore
|
||||
- name: Build
|
||||
run: dotnet build --no-restore
|
||||
run: dotnet build -c Release --no-restore
|
||||
- name: Publish
|
||||
run: dotnet publish --property:OutputPath=.\publish\
|
||||
- name: Upload artifact
|
||||
|
||||
64
.gitlab-ci.yml
Normal file
64
.gitlab-ci.yml
Normal file
@@ -0,0 +1,64 @@
|
||||
stages:
|
||||
- test
|
||||
- build
|
||||
- release
|
||||
|
||||
Test:
|
||||
stage: test
|
||||
image: mcr.microsoft.com/windows/server
|
||||
tags:
|
||||
- windows
|
||||
script:
|
||||
- dotnet restore
|
||||
- dotnet build -c Release --no-restore
|
||||
- dotnet publish --property:OutputPath=.\publish\
|
||||
- Move-Item -Path .\publish\publish\*.exe -Destination ..\ -Force
|
||||
|
||||
Build:
|
||||
stage: build
|
||||
only:
|
||||
- tags
|
||||
tags:
|
||||
- windows
|
||||
needs:
|
||||
- job: Test
|
||||
script:
|
||||
- echo "This is build stage."
|
||||
- Move-Item -Path ..\YaeAchievement.exe .\ -Force
|
||||
after_script:
|
||||
- echo "Current Job ID is $CI_JOB_ID"
|
||||
- echo "THIS_JOB_ID=$CI_JOB_ID" >> build.env
|
||||
artifacts:
|
||||
paths:
|
||||
- .\*.exe
|
||||
expire_in: 90 days
|
||||
reports:
|
||||
dotenv: build.env
|
||||
|
||||
|
||||
release:
|
||||
stage: release
|
||||
image: registry.gitlab.com/gitlab-org/release-cli:latest
|
||||
only:
|
||||
- tags
|
||||
needs:
|
||||
- job: Build
|
||||
artifacts: true
|
||||
variables:
|
||||
TAG: '$CI_COMMIT_TAG'
|
||||
script:
|
||||
- echo "Create Release $TAG"
|
||||
- echo "$THIS_JOB_ID"
|
||||
release:
|
||||
name: '$TAG'
|
||||
tag_name: '$TAG'
|
||||
ref: '$TAG'
|
||||
description: 'Release $TAG by CI'
|
||||
assets:
|
||||
links:
|
||||
- name: "YaeAchievement.exe"
|
||||
url: "https://$CI_SERVER_SHELL_SSH_HOST/$CI_PROJECT_PATH/-/jobs/$THIS_JOB_ID/artifacts/raw/YaeAchievement.exe?inline=false"
|
||||
link_type: package
|
||||
- name: ".NET 7.0 Desktop Runtime"
|
||||
url: "https://dotnet.microsoft.com/zh-cn/download/dotnet/thank-you/runtime-desktop-7.0.11-windows-x64-installer"
|
||||
link_type: other
|
||||
15
README.md
15
README.md
@@ -9,9 +9,22 @@
|
||||
|
||||
- 支持导出所有类别的成就
|
||||
- 支持官服,渠道服与国际服
|
||||
- 支持导出至[椰羊](https://cocogoat.work/achievement)、[Snap·HuTao](https://github.com/DGP-Studio/Snap.HuTao)、[Paimon.moe](https://paimon.moe/achievement/)、[Seelie.me](https://seelie.me/achievements)、[寻空](https://github.com/xunkong/xunkong)和表格文件(csv)
|
||||
- 没有窗口大小、游戏语言等要求
|
||||
|
||||
## 导出支持
|
||||
|
||||
> 按照数字键选择导出方式,<kbd>0</kbd> 为默认导出方式
|
||||
|
||||
0. [椰羊](https://cocogoat.work/achievement)
|
||||
1. [胡桃工具箱](https://github.com/DGP-Studio/Snap.HuTao)
|
||||
2. [Paimon.moe](https://paimon.moe/achievement/)
|
||||
3. [Seelie.me](https://seelie.me/achievements)
|
||||
4. 表格文件 `.csv`
|
||||
5. [寻空](https://github.com/xunkong/xunkong)
|
||||
6. [原魔工具箱](https://apps.apple.com/app/id1663989619)
|
||||
7. [TeyvatGuide](https://github.com/BTMuli/TeyvatGuide)
|
||||
8. [UIAF](https://uigf.org/standards/UIAF.html) JSON 文件
|
||||
|
||||
## 使用说明
|
||||
→ [Tutorial.md](Tutorial.md)
|
||||
|
||||
|
||||
15
README_EN.md
15
README_EN.md
@@ -13,9 +13,22 @@
|
||||
|
||||
- Support for exporting all categories of achievements
|
||||
- Supports all versions of Genshin Impact
|
||||
- Support for exporting to [Cocogoat](https://cocogoat.work/achievement), [Snap·HuTao](https://github.com/DGP-Studio/Snap.HuTao), [Paimon.moe](https://paimon.moe/achievement/), [Seelie.me](https://seelie.me/achievements)、[XunKong](https://github.com/xunkong/xunkong) and form files (csv)
|
||||
- There are no requirements for window size, game language, etc.
|
||||
|
||||
## Export support
|
||||
|
||||
> Select the export method according to the number keys, <kbd>0</kbd> is the default export method
|
||||
|
||||
0. [Cocogoat](https://cocogoat.work/achievement)
|
||||
1. [Snap HuTao](https://github.com/DGP-Studio/Snap.HuTao)
|
||||
2. [Paimon.moe](https://paimon.moe/achievement/)
|
||||
3. [Seelie.me](https://seelie.me/achievements)
|
||||
4. Form File `.csv`
|
||||
5. [XunKong](https://github.com/xunkong/xunkong)
|
||||
6. [YuanmoTools](https://apps.apple.com/app/id1663989619)
|
||||
7. [TeyvatGuide](https://github.com/BTMuli/TeyvatGuide)
|
||||
8. [UIAF](https://uigf.org/standards/UIAF.html) JSON file
|
||||
|
||||
## Instructions for Use:
|
||||
→ [Tutorial_EN.md](Tutorial_EN.md)
|
||||
|
||||
|
||||
12
Tutorial.md
12
Tutorial.md
@@ -71,11 +71,11 @@
|
||||
### 各种工具的介绍烦请移步至各工具的官方页面进行查看(下方序号对应导出序号)
|
||||
|
||||
0. [椰羊](https://cocogoat.work/achievement)
|
||||
|
||||
1. [Snap·HuTao](https://github.com/DGP-Studio/Snap.HuTao)
|
||||
|
||||
1. [胡桃工具箱](https://github.com/DGP-Studio/Snap.HuTao)
|
||||
2. [Paimon.moe](https://paimon.moe/achievement/)
|
||||
|
||||
3. [Seelie.me](https://seelie.me/achievements)
|
||||
|
||||
4. [寻空](https://github.com/xunkong/xunkong)
|
||||
4. ~~表格文件 `.csv`~~
|
||||
5. [寻空](https://github.com/xunkong/xunkong)
|
||||
6. [原魔工具箱](https://apps.apple.com/app/id1663989619)
|
||||
7. [TeyvatGuide](https://github.com/BTMuli/TeyvatGuide)
|
||||
8. [UIAF](https://uigf.org/standards/UIAF.html) JSON 文件
|
||||
|
||||
@@ -65,9 +65,12 @@ At this time, you can select the Achievements in the left column to view the imp
|
||||
|
||||
### For the introduction of different tools, please visit the official page of each tool to see:
|
||||
|
||||
1. [Snap·HuTao](https://github.com/DGP-Studio/Snap.HuTao)
|
||||
|
||||
0. [Cocogoat](https://cocogoat.work/achievement)
|
||||
1. [Snap HuTao](https://github.com/DGP-Studio/Snap.HuTao)
|
||||
2. [Paimon.moe](https://paimon.moe/achievement/)
|
||||
|
||||
3. [Seelie.me](https://seelie.me/achievements)
|
||||
|
||||
4. ~~Form File `.csv`~~
|
||||
5. [XunKong](https://github.com/xunkong/xunkong)
|
||||
6. [YuanmoTools](https://apps.apple.com/app/id1663989619)
|
||||
7. [Teyvat Guide](https://github.com/BTMuli/TeyvatGuide)
|
||||
8. [UIAF](https://uigf.org/standards/UIAF.html) JSON file
|
||||
|
||||
@@ -110,12 +110,11 @@
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="src\HookManager.h" />
|
||||
<ClInclude Include="src\il2cpp-api-functions.h" />
|
||||
<ClInclude Include="src\il2cpp-appdata.h" />
|
||||
<ClInclude Include="src\il2cpp-functions.h" />
|
||||
<ClInclude Include="src\il2cpp-types-ptr.h" />
|
||||
<ClInclude Include="src\il2cpp-types.h" />
|
||||
<ClInclude Include="src\il2cpp-init.h" />
|
||||
<ClInclude Include="src\il2cpp-unity-functions.h" />
|
||||
<ClInclude Include="src\pch.h" />
|
||||
<ClInclude Include="src\util.h" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -1,106 +1,63 @@
|
||||
#include "pch.h"
|
||||
// ReSharper disable CppCStyleCast
|
||||
// ReSharper disable CppInconsistentNaming
|
||||
// ReSharper disable CppClangTidyModernizeUseStdPrint
|
||||
// ReSharper disable CppClangTidyClangDiagnosticCastAlign
|
||||
// ReSharper disable CppClangTidyHicppMultiwayPathsCovered
|
||||
// ReSharper disable CppDefaultCaseNotHandledInSwitchStatement
|
||||
// ReSharper disable CppClangTidyClangDiagnosticCastFunctionTypeStrict
|
||||
|
||||
#include "pch.h"
|
||||
#include "util.h"
|
||||
#include "il2cpp-init.h"
|
||||
|
||||
using Genshin::ByteArray, Genshin::ClientKcpEvent, Genshin::KcpPacket, Genshin::KcpEventType;
|
||||
using std::to_string;
|
||||
using Genshin::ByteArray;
|
||||
|
||||
HWND unityWnd = nullptr;
|
||||
HANDLE hPipe = nullptr;
|
||||
|
||||
// Allow Protocol: GetPlayerToken, PlayerLogin, AchievementAllDataNotify, Ping, PlayerForceExit
|
||||
std::set<UINT16> PacketWhitelist = { 6929, 7187, 4356, 6011, 1268, 24845, 24404, 29313 };
|
||||
|
||||
bool OnPacket(KcpPacket* pkt) {
|
||||
if (pkt->data == nullptr) return true;
|
||||
auto len = pkt->length;
|
||||
auto data = (ByteArray*)new BYTE[len + 32];
|
||||
data->max_length = len;
|
||||
memcpy(data->vector, pkt->data, len);
|
||||
Genshin::XorEncrypt(&data, len, nullptr);
|
||||
if (ReadMapped<UINT16>(data->vector, 0) != 0x4567) {
|
||||
delete[] data;
|
||||
return true;
|
||||
}
|
||||
if (!PacketWhitelist.contains(ReadMapped<UINT16>(data->vector, 2))) {
|
||||
//ifdef _DEBUG
|
||||
printf("Blocked cmdid: %d\n", ReadMapped<UINT16>(data->vector, 2));
|
||||
//endif
|
||||
delete[] data;
|
||||
return false;
|
||||
}
|
||||
printf("Passed cmdid: %d\n", ReadMapped<UINT16>(data->vector, 2));
|
||||
if (ReadMapped<UINT16>(data->vector, 2) == 1268) {
|
||||
auto headLength = ReadMapped<UINT16>(data->vector, 4);
|
||||
auto dataLength = ReadMapped<UINT32>(data->vector, 6);
|
||||
auto iStr = Genshin::ToBase64String(data, 10 + headLength, dataLength, nullptr);
|
||||
auto cStr = ToString(iStr) + "\n";
|
||||
WriteFile(hPipe, cStr.c_str(), cStr.length(), nullptr, nullptr);
|
||||
CloseHandle(hPipe);
|
||||
auto manager = Genshin::GetSingletonInstance(Genshin::GetSingletonManager(), il2cpp_string_new("GameManager"));
|
||||
Genshin::ForceQuit(manager);
|
||||
}
|
||||
delete[] data;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string checksum;
|
||||
|
||||
namespace Hook {
|
||||
|
||||
int KcpSend(void* client, KcpPacket* pkt, void* method) {
|
||||
return OnPacket(pkt) ? CALL_ORIGIN(KcpSend, client, pkt, method) : 0;
|
||||
}
|
||||
|
||||
void SetVersion(void* obj, Il2CppString* value, void* method) {
|
||||
auto version = ToString(value);
|
||||
value = string_new(version + " YaeAchievement");
|
||||
CALL_ORIGIN(SetVersion, obj, value, method);
|
||||
}
|
||||
|
||||
bool KcpRecv(void* client, ClientKcpEvent* evt, void* method) {
|
||||
auto result = CALL_ORIGIN(KcpRecv, client, evt, method);
|
||||
if (result == 0 || evt->fields.type != KcpEventType::EventRecvMsg) {
|
||||
return result;
|
||||
ByteArray* UnityEngine_RecordUserData(const INT type) {
|
||||
if (type == 0) {
|
||||
const auto arr = new ByteArray {};
|
||||
const auto len = checksum.length();
|
||||
arr->max_length = len;
|
||||
memcpy(&arr->vector[0], checksum.data(), len);
|
||||
return arr;
|
||||
}
|
||||
return OnPacket(evt->fields.packet) ? result : false;
|
||||
return new ByteArray {};
|
||||
}
|
||||
|
||||
ByteArray* UnityEngine_RecordUserData(INT type) {
|
||||
return Genshin::GetBytes(Genshin::GetDefaultEncoding(), il2cpp_string_new(""));
|
||||
}
|
||||
|
||||
VOID SetChecksum(LPVOID obj, Il2CppString* value) {
|
||||
CALL_ORIGIN(SetChecksum, obj, il2cpp_string_new(checksum.c_str()));
|
||||
}
|
||||
|
||||
VOID RequestLogin(LPVOID obj, LPVOID token, UINT32 uid) {
|
||||
HookManager::install(Genshin::SetChecksum, SetChecksum);
|
||||
CALL_ORIGIN(RequestLogin, obj, token, uid);
|
||||
HookManager::detach(SetChecksum);
|
||||
|
||||
void OnAchievementAllDataNotify(LPVOID obj, const LPVOID ntf) {
|
||||
const auto cos = Genshin::il2cpp_object_new(*Genshin::CodedOutputStream__TypeInfo);
|
||||
const auto len = Genshin::CalculateSize(ntf);
|
||||
const auto buf = (ByteArray*) new uint8_t[0x20 + len] {};
|
||||
buf->max_length = len;
|
||||
Genshin::CodedOutputStreamInit(cos, buf, 0, len);
|
||||
Genshin::ProtoWriteTo(ntf, cos);
|
||||
const auto str = base64_encode(buf->vector, len) + "\n";
|
||||
WriteFile(hPipe, str.c_str(), (DWORD) str.length(), nullptr, nullptr);
|
||||
CloseHandle(hPipe);
|
||||
ExitProcess(0);
|
||||
}
|
||||
}
|
||||
|
||||
void Run(HMODULE* phModule) {
|
||||
//AllocConsole();
|
||||
//freopen_s((FILE**)stdout, "CONOUT$", "w", stdout);
|
||||
while (
|
||||
GetModuleHandle("UserAssembly.dll") == nullptr ||
|
||||
(unityWnd = FindMainWindowByPID(GetCurrentProcessId())) == nullptr
|
||||
) {
|
||||
while ((unityWnd = FindMainWindowByPID(GetCurrentProcessId())) == nullptr) {
|
||||
Sleep(1000);
|
||||
}
|
||||
Sleep(5000);
|
||||
DisableVMProtect();
|
||||
InitIL2CPP();
|
||||
auto enc = Genshin::GetDefaultEncoding();
|
||||
for (int i = 0; i < 3; i++) {
|
||||
checksum += ToString(Genshin::GetString(enc, Genshin::RecordUserData(i)));
|
||||
const auto result = Genshin::RecordUserData(i);
|
||||
checksum += string(reinterpret_cast<char*>(&result->vector[0]), result->max_length);
|
||||
}
|
||||
HookManager::install(Genshin::KcpSend, Hook::KcpSend);
|
||||
HookManager::install(Genshin::KcpRecv, Hook::KcpRecv);
|
||||
HookManager::install(Genshin::SetVersion, Hook::SetVersion);
|
||||
HookManager::install(Genshin::RequestLogin, Hook::RequestLogin);
|
||||
HookManager::install(Genshin::OnAchievementAllDataNotify, Hook::OnAchievementAllDataNotify);
|
||||
HookManager::install(Genshin::UnityEngine_RecordUserData, Hook::UnityEngine_RecordUserData);
|
||||
hPipe = CreateFile(R"(\\.\pipe\YaeAchievementPipe)", GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr);
|
||||
if (hPipe == INVALID_HANDLE_VALUE) {
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
DO_API(0x941c20, 0x93e230, Il2CppString*, il2cpp_string_new, (const char* str));
|
||||
@@ -1,20 +1,19 @@
|
||||
// ReSharper disable CppClangTidyBugproneMacroParentheses
|
||||
|
||||
#pragma once
|
||||
#include "il2cpp-types.h"
|
||||
|
||||
// IL2CPP APIs
|
||||
#define DO_API(ca, oa, r, n, p) extern r (*n) p
|
||||
#include "il2cpp-api-functions.h"
|
||||
#undef DO_API
|
||||
|
||||
// Application-specific functions
|
||||
#define DO_APP_FUNC(ca, oa, r, n, p) extern r (*n) p
|
||||
#define DO_UNI_FUNC(ca, oa, r, n, p) extern r (*n) p
|
||||
namespace Genshin {
|
||||
#include "il2cpp-functions.h"
|
||||
}
|
||||
#undef DO_UNI_FUNC
|
||||
#undef DO_APP_FUNC
|
||||
|
||||
#define DO_UNI_FUNC(ca, oa, r, n, p) extern r (*n) p
|
||||
#define DO_TYPEDEF(ca, oa, n) extern n##__Class **n##__TypeInfo
|
||||
namespace Genshin {
|
||||
#include "il2cpp-unity-functions.h"
|
||||
#include "il2cpp-types-ptr.h"
|
||||
}
|
||||
#undef DO_UNI_FUNC
|
||||
#undef DO_TYPEDEF
|
||||
@@ -2,30 +2,16 @@ using namespace Genshin;
|
||||
|
||||
// DO_APP_FUNC(CN_OFFSET, OS_OFFSET, RETURN, FUNC_NAME, (ARGS...));
|
||||
|
||||
DO_APP_FUNC(0x728b850, 0x7247520, Il2CppString*, ToBase64String, (ByteArray* value, int offset, int length, void* method));
|
||||
DO_APP_FUNC(0x4F1EF0, 0x545600, LPVOID, il2cpp_object_new, (LPVOID t));
|
||||
|
||||
DO_APP_FUNC(0x215d110, 0x214d7a0, void, SetVersion, (void* obj, Il2CppString* value, void* method));
|
||||
DO_APP_FUNC(0x052818B0, 0x0529E520, ByteArray*, RecordUserData, (int32_t nType));
|
||||
|
||||
DO_APP_FUNC(0x7b4dc00, 0x7afe4e0, ByteArray*, RecordUserData, (int32_t nType));
|
||||
DO_APP_FUNC(0x05DCBE60, 0x05DF2F40, void, OnAchievementAllDataNotify, (LPVOID obj, LPVOID ntf));
|
||||
|
||||
DO_APP_FUNC(0x166e5d0, 0x1662f60, void, XorEncrypt, (ByteArray** data, int length, void* method));
|
||||
DO_APP_FUNC(0x043EC0B0, 0x043FA380, int, CalculateSize, (LPVOID obj));
|
||||
|
||||
DO_APP_FUNC(0xf71860, 0xf69870, int, KcpSend, (void* client, KcpPacket* pkt, void* method));
|
||||
DO_APP_FUNC(0x043EBFF0, 0x043FA2C0, void, ProtoWriteTo, (LPVOID obj, LPVOID output));
|
||||
|
||||
DO_APP_FUNC(0x433e670, 0x4315590, bool, KcpRecv, (void* client, ClientKcpEvent* evt, void* method));
|
||||
DO_APP_FUNC(0x06F08220, 0x06F3F280, void, CodedOutputStreamInit, (LPVOID obj, LPVOID buffer, int offset, int length));
|
||||
|
||||
DO_APP_FUNC(0x75627b0, 0x751a960, LPVOID, GetDefaultEncoding, ());
|
||||
|
||||
DO_APP_FUNC(0x7561ff0, 0x751a1c0, Il2CppString*, GetString, (LPVOID encoding, LPVOID bytes));
|
||||
|
||||
DO_APP_FUNC(0x7560d90, 0x7518f90, ByteArray*, GetBytes, (LPVOID encoding, LPVOID str));
|
||||
|
||||
DO_APP_FUNC(0x1349850, 0x13415f0, VOID, RequestLogin, (LPVOID obj, LPVOID token, UINT uid));
|
||||
|
||||
DO_APP_FUNC(0x11ab1d0, 0x3e9f710, VOID, SetChecksum, (LPVOID obj, Il2CppString* value));
|
||||
|
||||
DO_APP_FUNC(0xd4e730, 0xd49dd0, VOID, ForceQuit, (LPVOID obj));
|
||||
|
||||
DO_APP_FUNC(0x607fbf0, 0x6044870, LPVOID, GetSingletonManager, ());
|
||||
|
||||
DO_APP_FUNC(0x607f920, 0x60445a0, LPVOID, GetSingletonInstance, (LPVOID obj, Il2CppString* value));
|
||||
DO_UNI_FUNC(0x105970, 0x105970, ByteArray*, UnityEngine_RecordUserData, (int32_t nType));
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
// ReSharper disable CppClangTidyBugproneMacroParentheses
|
||||
|
||||
#include "pch.h"
|
||||
|
||||
#include "il2cpp-init.h"
|
||||
|
||||
#define DO_API(ca, oa, r, n, p) r (*n) p
|
||||
#include "il2cpp-api-functions.h"
|
||||
#undef DO_API
|
||||
|
||||
#define DO_APP_FUNC(ca, oa, r, n, p) r (*n) p
|
||||
#define DO_UNI_FUNC(ca, oa, r, n, p) r (*n) p
|
||||
namespace Genshin {
|
||||
#include "il2cpp-functions.h"
|
||||
}
|
||||
#undef DO_UNI_FUNC
|
||||
#undef DO_APP_FUNC
|
||||
|
||||
#define DO_UNI_FUNC(ca, oa, r, n, p) r (*n) p
|
||||
#define DO_TYPEDEF(ca, oa, n) n##__Class **n##__TypeInfo
|
||||
namespace Genshin {
|
||||
#include "il2cpp-unity-functions.h"
|
||||
#include "il2cpp-types-ptr.h"
|
||||
}
|
||||
#undef DO_UNI_FUNC
|
||||
#undef DO_TYPEDEF
|
||||
|
||||
using std::string;
|
||||
|
||||
@@ -27,13 +27,12 @@ void InitIL2CPP() {
|
||||
auto hBase = GetModuleHandle("UserAssembly.dll");
|
||||
auto bAddr = (UINT64)hBase;
|
||||
auto cAddr = (UINT64)GetModuleHandle("UnityPlayer.dll");
|
||||
#define DO_API(ca, oa, r, n, p) n = (r (*) p)(bAddr + (isCN ? ca : oa))
|
||||
#include "il2cpp-api-functions.h"
|
||||
#undef DO_API
|
||||
#define DO_APP_FUNC(ca, oa, r, n, p) n = (r (*) p)(bAddr + (isCN ? ca : oa))
|
||||
#include "il2cpp-functions.h"
|
||||
#undef DO_APP_FUNC
|
||||
#define DO_UNI_FUNC(ca, oa, r, n, p) n = (r (*) p)(cAddr + (isCN ? ca : oa))
|
||||
#include "il2cpp-unity-functions.h"
|
||||
#include "il2cpp-functions.h"
|
||||
#undef DO_UNI_FUNC
|
||||
#undef DO_APP_FUNC
|
||||
#define DO_TYPEDEF(ca, oa, n) n##__TypeInfo = (n##__Class **)(bAddr + (isCN ? ca : oa))
|
||||
#include "il2cpp-types-ptr.h"
|
||||
#undef DO_TYPEDEF
|
||||
}
|
||||
|
||||
2
lib/src/il2cpp-types-ptr.h
Normal file
2
lib/src/il2cpp-types-ptr.h
Normal file
@@ -0,0 +1,2 @@
|
||||
// LFGDACFKABF
|
||||
DO_TYPEDEF(0x2965BA0, 0, CodedOutputStream);
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,3 +0,0 @@
|
||||
using namespace Genshin;
|
||||
|
||||
DO_UNI_FUNC(0x100560, 0x100560, ByteArray*, UnityEngine_RecordUserData, (int32_t nType));
|
||||
@@ -68,3 +68,38 @@ HWND FindMainWindowByPID(DWORD pid) {
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
static const std::string base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
std::string base64_encode(BYTE const* buf, unsigned int bufLen) {
|
||||
std::string ret;
|
||||
int i = 0;
|
||||
BYTE char_array_3[3];
|
||||
BYTE char_array_4[4];
|
||||
while (bufLen--) {
|
||||
char_array_3[i++] = *buf++;
|
||||
if (i == 3) {
|
||||
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
|
||||
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
|
||||
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
|
||||
char_array_4[3] = char_array_3[2] & 0x3f;
|
||||
for (i = 0; (i < 4); i++)
|
||||
ret += base64_chars[char_array_4[i]];
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
if (i) {
|
||||
int j;
|
||||
for (j = i; j < 3; j++)
|
||||
char_array_3[j] = '\0';
|
||||
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
|
||||
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
|
||||
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
|
||||
char_array_4[3] = char_array_3[2] & 0x3f;
|
||||
for (j = 0; j < i + 1; j++)
|
||||
ret += base64_chars[char_array_4[j]];
|
||||
while (i++ < 3)
|
||||
ret += '=';
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -6,9 +6,7 @@ VOID DisableVMProtect();
|
||||
bool IsLittleEndian();
|
||||
HWND FindMainWindowByPID(DWORD pid);
|
||||
string ToString(Il2CppString* str, UINT codePage = CP_ACP);
|
||||
|
||||
#define cstring_new(str) il2cpp_string_new(str)
|
||||
#define string_new(str) cstring_new((str).c_str())
|
||||
std::string base64_encode(BYTE const* buf, unsigned int bufLen);
|
||||
|
||||
#define ErrorDialogT(title, msg) MessageBox(unityWnd, msg, title, MB_OK | MB_ICONERROR | MB_SYSTEMMODAL);
|
||||
#define ErrorDialog(msg) ErrorDialogT("YaeAchievement", msg)
|
||||
|
||||
22
res/App.Designer.cs
generated
22
res/App.Designer.cs
generated
@@ -121,7 +121,9 @@ namespace YaeAchievement.res {
|
||||
///[3] Seelie.me
|
||||
///[4] Csv file
|
||||
///[5] Xunkong
|
||||
///Input a number (0-5): .
|
||||
///[7] Teyvat Guide
|
||||
///[8] UIAF JSON File
|
||||
///Input a number (0-8): .
|
||||
/// </summary>
|
||||
internal static string ExportChoose {
|
||||
get {
|
||||
@@ -174,6 +176,24 @@ namespace YaeAchievement.res {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Please launch/update Teyvat Guide and retry..
|
||||
/// </summary>
|
||||
internal static string ExportToTauriFail {
|
||||
get {
|
||||
return ResourceManager.GetString("ExportToTauriFail", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Successfully exported to Teyvat Guide..
|
||||
/// </summary>
|
||||
internal static string ExportToTauriSuccess {
|
||||
get {
|
||||
return ResourceManager.GetString("ExportToTauriSuccess", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to {0}.
|
||||
/// </summary>
|
||||
|
||||
10
res/App.resx
10
res/App.resx
@@ -32,7 +32,9 @@
|
||||
[3] Seelie.me
|
||||
[4] Csv file
|
||||
[5] Xunkong
|
||||
Input a number (0-5): </value>
|
||||
[7] Teyvat Guide
|
||||
[8] UIAF JSON File
|
||||
Input a number (0-8): </value>
|
||||
</data>
|
||||
<data name="ExportToCocogoatSuccess" xml:space="preserve">
|
||||
<value>Successfully exported to cocogoat.</value>
|
||||
@@ -129,4 +131,10 @@ Input a number (0-5): </value>
|
||||
<data name="NoWritePermission" xml:space="preserve">
|
||||
<value>No write permission on {0}.</value>
|
||||
</data>
|
||||
<data name="ExportToTauriSuccess" xml:space="preserve">
|
||||
<value>Successfully exported to Teyvat Guide.</value>
|
||||
</data>
|
||||
<data name="ExportToTauriFail" xml:space="preserve">
|
||||
<value>Please launch/update Teyvat Guide and retry.</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -26,8 +26,9 @@
|
||||
[4] 表格文件
|
||||
[5] 寻空
|
||||
[6] 原魔工具箱
|
||||
[7] UIAF JSON 文件
|
||||
输入一个数字 (0-7): </value>
|
||||
[7] Teyvat Guide
|
||||
[8] UIAF JSON 文件
|
||||
输入一个数字 (0-8): </value>
|
||||
</data>
|
||||
<data name="ExportToCocogoatSuccess" xml:space="preserve">
|
||||
<value>在浏览器内进行下一步操作</value>
|
||||
@@ -115,9 +116,15 @@
|
||||
<value>网络错误,请检查网络后重试 ({0}: {1})</value>
|
||||
</data>
|
||||
<data name="GenshinHashError" xml:space="preserve">
|
||||
<value>请将原神更新至最新版本后重试</value>
|
||||
<value>当前适配版本不匹配,请更新原神至最新版本后重试或等待工具更新。</value>
|
||||
</data>
|
||||
<data name="NoWritePermission" xml:space="preserve">
|
||||
<value>无法写入文件,请更换软件所在目录后重试</value>
|
||||
</data>
|
||||
<data name="ExportToTauriFail" xml:space="preserve">
|
||||
<value>启动 Teyvat Guide 或更新 Teyvat Guide 至最新版本后重试</value>
|
||||
</data>
|
||||
<data name="ExportToTauriSuccess" xml:space="preserve">
|
||||
<value>在 Teyvat Guide 进行下一步操作</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -9,13 +9,13 @@ message Achievement {
|
||||
FINISHED = 2;
|
||||
REWARD_TAKEN = 3;
|
||||
}
|
||||
uint32 timestamp = 3;
|
||||
uint32 current = 9;
|
||||
uint32 total = 11;
|
||||
uint32 timestamp = 11;
|
||||
uint32 current = 15;
|
||||
uint32 total = 3;
|
||||
uint32 id = 14;
|
||||
Status status = 10;
|
||||
Status status = 8;
|
||||
}
|
||||
|
||||
message AchievementAllDataNotify {
|
||||
repeated Achievement list = 3;
|
||||
repeated Achievement list = 9;
|
||||
}
|
||||
|
||||
@@ -32,8 +32,9 @@ public static class Export {
|
||||
4 => ToCSV,
|
||||
5 => ToXunkong,
|
||||
6 => ToWxApp1,
|
||||
7 => ToUIAFJson,
|
||||
8 => ToRawJson,
|
||||
7 => ToTeyvatGuide,
|
||||
8 => ToUIAFJson,
|
||||
9 => ToRawJson,
|
||||
_ => ToCocogoat
|
||||
})).Invoke(data);
|
||||
}
|
||||
@@ -77,19 +78,38 @@ public static class Export {
|
||||
}
|
||||
|
||||
private static void ToHuTao(AchievementAllDataNotify data) {
|
||||
if (CheckWinUIAppScheme("hutao"))
|
||||
{
|
||||
if (CheckWinUIAppScheme("hutao")) {
|
||||
Utils.CopyToClipboard(JsonSerializer.Serialize(ExportToUIAFApp(data)));
|
||||
Utils.ShellOpen("hutao://achievement/import");
|
||||
Console.WriteLine(App.ExportToSnapGenshinSuccess);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
Console.WriteLine(App.ExportToSnapGenshinNeedUpdate);
|
||||
Utils.ShellOpen("ms-windows-store://pdp/?productid=9PH4NXJ2JN52");
|
||||
}
|
||||
}
|
||||
|
||||
private static void ToXunkong(AchievementAllDataNotify data) {
|
||||
if (CheckWinUIAppScheme("xunkong")) {
|
||||
Utils.CopyToClipboard(JsonSerializer.Serialize(ExportToUIAFApp(data)));
|
||||
Utils.ShellOpen("xunkong://import-achievement?caller=YaeAchievement&from=clipboard");
|
||||
Console.WriteLine(App.ExportToXunkongSuccess);
|
||||
} else {
|
||||
Console.WriteLine(App.ExportToXunkongNeedUpdate);
|
||||
Utils.ShellOpen("ms-windows-store://pdp/?productid=9N2SVG0JMT12");
|
||||
}
|
||||
}
|
||||
|
||||
private static void ToTeyvatGuide(AchievementAllDataNotify data) {
|
||||
if (Process.GetProcessesByName("TeyvatGuide").Any()) {
|
||||
Utils.CopyToClipboard(JsonSerializer.Serialize(ExportToUIAFApp(data)));
|
||||
Utils.ShellOpen("teyvatguide://import_uigf?app=YaeAchievement");
|
||||
Console.WriteLine(App.ExportToTauriSuccess);
|
||||
} else {
|
||||
Console.WriteLine(App.ExportToTauriFail);
|
||||
Utils.ShellOpen("ms-windows-store://pdp/?productid=9NLBNNNBNSJN");
|
||||
}
|
||||
}
|
||||
|
||||
// ReSharper disable once InconsistentNaming
|
||||
private static void ToUIAFJson(AchievementAllDataNotify data) {
|
||||
var path = Path.GetFullPath($"uiaf-{DateTime.Now:yyyyMMddHHmmss}.json");
|
||||
@@ -168,17 +188,6 @@ public static class Export {
|
||||
}
|
||||
}
|
||||
|
||||
private static void ToXunkong(AchievementAllDataNotify data) {
|
||||
if (CheckWinUIAppScheme("xunkong")) {
|
||||
Utils.CopyToClipboard(JsonSerializer.Serialize(ExportToUIAFApp(data)));
|
||||
Utils.ShellOpen("xunkong://import-achievement?caller=YaeAchievement&from=clipboard");
|
||||
Console.WriteLine(App.ExportToXunkongSuccess);
|
||||
} else {
|
||||
Console.WriteLine(App.ExportToXunkongNeedUpdate);
|
||||
Utils.ShellOpen("ms-windows-store://pdp/?productid=9N2SVG0JMT12");
|
||||
}
|
||||
}
|
||||
|
||||
private static void ToRawJson(AchievementAllDataNotify data) {
|
||||
var path = Path.GetFullPath($"export-{DateTime.Now:yyyyMMddHHmmss}-raw.json");
|
||||
var text = JsonSerializer.Serialize(data, new JsonSerializerOptions {
|
||||
|
||||
@@ -20,8 +20,8 @@ public static class GlobalVars {
|
||||
public static readonly string CachePath = Path.Combine(DataPath, "cache");
|
||||
public static readonly string LibFilePath = Path.Combine(DataPath, "YaeAchievement.dll");
|
||||
|
||||
public const uint AppVersionCode = 39;
|
||||
public const string AppVersionName = "2.9";
|
||||
public const uint AppVersionCode = 43;
|
||||
public const string AppVersionName = "3.3";
|
||||
|
||||
public const string PipeName = "YaeAchievementPipe";
|
||||
public const string BucketHost = "https://cn-cd-1259389942.file.myqcloud.com";
|
||||
|
||||
@@ -45,7 +45,7 @@ public static class Injector {
|
||||
return new Win32Exception().PrintMsgAndReturnErrCode("WriteProcessMemory fail");
|
||||
}
|
||||
}
|
||||
var lpStartAddress = pLoadLibrary.CreateDelegate<LPTHREAD_START_ROUTINE>();
|
||||
var lpStartAddress = (delegate* unmanaged[Stdcall]<void*, uint>)pLoadLibrary.Value; //THREAD_START_ROUTINE
|
||||
var hThread = Native.CreateRemoteThread(hProc, default, 0, lpStartAddress, pBase, 0);
|
||||
if (hThread.IsNull) {
|
||||
var e = new Win32Exception();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"$schema": "https://aka.ms/CsWin32.schema.json",
|
||||
"className": "Native",
|
||||
"allowMarshaling": true,
|
||||
"allowMarshaling": false,
|
||||
"public": true
|
||||
}
|
||||
@@ -1,21 +1,21 @@
|
||||
CreateProcess
|
||||
CloseClipboard
|
||||
CreateProcess
|
||||
CreateRemoteThread
|
||||
EmptyClipboard
|
||||
GetConsoleMode
|
||||
GetDC
|
||||
GetDeviceCaps
|
||||
GetModuleHandle
|
||||
GetProcAddress
|
||||
VirtualAllocEx
|
||||
WriteProcessMemory
|
||||
CreateRemoteThread
|
||||
VirtualFreeEx
|
||||
WaitForSingleObject
|
||||
OpenClipboard
|
||||
EmptyClipboard
|
||||
GlobalLock
|
||||
SetClipboardData
|
||||
GlobalUnlock
|
||||
CloseClipboard
|
||||
GetStdHandle
|
||||
GetConsoleMode
|
||||
GlobalLock
|
||||
GlobalUnlock
|
||||
OpenClipboard
|
||||
ResumeThread
|
||||
SetClipboardData
|
||||
SetConsoleMode
|
||||
TerminateProcess
|
||||
ResumeThread
|
||||
GetDeviceCaps
|
||||
GetDC
|
||||
VirtualAllocEx
|
||||
VirtualFreeEx
|
||||
WaitForSingleObject
|
||||
WriteProcessMemory
|
||||
@@ -92,7 +92,7 @@ public static class Utils {
|
||||
|
||||
public static void CheckUpdate(bool useLocalLib) {
|
||||
var info = UpdateInfo.Parser.ParseFrom(GetBucketFileAsByteArray("schicksal/version"))!;
|
||||
if (GlobalVars.AppVersionCode != info.VersionCode) {
|
||||
if (GlobalVars.AppVersionCode < info.VersionCode) {
|
||||
Console.WriteLine(App.UpdateNewVersion, GlobalVars.AppVersionName, info.VersionName);
|
||||
Console.WriteLine(App.UpdateDescription, info.Description);
|
||||
if (info.EnableAutoDownload) {
|
||||
|
||||
Reference in New Issue
Block a user