15 Commits
2.2.0 ... 2.4.1

Author SHA1 Message Date
HolographicHat
31b77a9fb3 fix empty result and bump version to 2.4.1 2022-12-07 23:36:18 +08:00
HolographicHat
d2d5bafcd6 v2.4 2022-12-07 13:02:22 +08:00
HolographicHat
e2f1f1e343 lib for 3.3 2022-12-07 12:13:27 +08:00
HolographicHat
349e15fe25 v2.3 2022-11-02 09:31:18 +08:00
HolographicHat
9e0d18910b improve user experience 2022-11-01 11:11:11 +08:00
HolographicHat
afee99fd3f native lib 3.2 2022-11-01 10:26:18 +08:00
HolographicHat
4dae8c52b6 Update actions/upload-artifact 2022-10-17 08:39:35 +08:00
HolographicHat
3294ac4b89 add try catch 2022-10-17 08:19:21 +08:00
HolographicHat
ccb19c832c ignore tmp file delete exception 2022-10-08 19:41:39 +08:00
HolographicHat
1207dd70b3 Add game executable hash check 2022-10-03 16:33:58 +08:00
HolographicHat
204f211249 bump version to 2.2.1 2022-10-02 13:20:18 +08:00
HolographicHat
043a861030 improve update 2022-10-02 13:19:54 +08:00
HolographicHat
09a9d4c22b fix crash 2022-10-02 00:39:45 +08:00
HolographicHat
9094b9c718 update 2022-10-01 20:03:03 +08:00
HolographicHat
d7ac18587a snapgenshin -> snaphutao 2022-09-29 21:03:44 +08:00
23 changed files with 301 additions and 538 deletions

View File

@@ -24,7 +24,7 @@ jobs:
- name: Publish
run: dotnet publish -o .\publish\
- name: Upload artifact
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v3.1.0
with:
name: Artifacts
path: publish

View File

@@ -30,6 +30,10 @@
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>App.Designer.cs</LastGenOutput>
</EmbeddedResource>
<None Remove="res\Updater.exe" />
<EmbeddedResource Include="res\Updater.exe">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>

View File

@@ -105,7 +105,7 @@
<AdditionalDependencies>detours-x64.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PostBuildEvent>
<Command>copy $(TargetPath) $(ProjectDir)..\bin\Debug\net6.0\win-x64</Command>
<Command>copy $(TargetPath) $(ProjectDir)..\bin\Debug\net6.0\win-x64\YaeAchievementLib.dll /y</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>

View File

@@ -8,7 +8,7 @@ using std::to_string;
HWND unityWnd = 0;
HANDLE hPipe = 0;
std::set<UINT16> PacketWhitelist = { 172, 198, 112, 2676, 7, 21, 135 }; // ping, token, loginreq
std::set<UINT16> PacketWhitelist = { 179, 130, 156, 2692, 100, 43, 119 }; // ping, token, loginreq
bool OnPacket(KcpPacket* pkt) {
if (pkt->data == nullptr) return true;
@@ -29,7 +29,7 @@ bool OnPacket(KcpPacket* pkt) {
return false;
}
printf("Passed cmdid: %d\n", ReadMapped<UINT16>(data->vector, 2));
if (ReadMapped<UINT16>(data->vector, 2) == 2676) {
if (ReadMapped<UINT16>(data->vector, 2) == 2692) {
auto headLength = ReadMapped<UINT16>(data->vector, 4);
auto dataLength = ReadMapped<UINT32>(data->vector, 6);
auto iStr = Genshin::ToBase64String(data, 10 + headLength, dataLength, nullptr);
@@ -42,6 +42,8 @@ bool OnPacket(KcpPacket* pkt) {
return true;
}
std::map<INT, UINT> signatures;
namespace Hook {
int KcpSend(void* client, KcpPacket* pkt, void* method) {
@@ -62,21 +64,14 @@ namespace Hook {
return OnPacket(evt->fields.packet) ? result : false;
}
std::map<INT, UINT> signatures;
ByteArray* UnityEngine_RecordUserData(INT type) {
if (signatures.count(type)) {
return GCHandle_GetObject<ByteArray>(signatures[type]);
}
auto result = CALL_ORIGIN(UnityEngine_RecordUserData, type);
signatures[type] = GCHandle_New(result, true);
return result;
return GCHandle_GetObject<ByteArray>(signatures[type]);
}
}
void Run(HMODULE* phModule) {
AllocConsole();
freopen_s((FILE**)stdout, "CONOUT$", "w", stdout);
//AllocConsole();
//freopen_s((FILE**)stdout, "CONOUT$", "w", stdout);
while (
GetModuleHandle("UserAssembly.dll") == nullptr ||
(unityWnd = FindMainWindowByPID(GetCurrentProcessId())) == 0
@@ -84,14 +79,17 @@ void Run(HMODULE* phModule) {
Sleep(1000);
}
Sleep(5000);
DisableVMProtect();
InitIL2CPP();
HookManager::install(Genshin::UnityEngine_RecordUserData, Hook::UnityEngine_RecordUserData);
for (int i = 0; i < 4; i++) {
Genshin::RecordUserData(i, nullptr);
auto result = Genshin::RecordUserData(i, nullptr);
signatures[i] = GCHandle_New(result, true);
}
signatures[3] = signatures[2];
HookManager::install(Genshin::KcpSend, Hook::KcpSend);
HookManager::install(Genshin::KcpRecv, Hook::KcpRecv);
HookManager::install(Genshin::SetVersion, Hook::SetVersion);
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) {
Win32ErrorDialog(1001);

View File

@@ -1,310 +1,3 @@
#ifndef DO_API_NO_RETURN
#define DO_API_NO_RETURN(r, n, p) DO_API(r,n,p)
#endif
#pragma region General
DO_API(int, il2cpp_init, (const char* domain_name));
DO_API(int, il2cpp_init_utf16, (const Il2CppChar* domain_name));
DO_API(void, il2cpp_shutdown, ());
DO_API(void, il2cpp_set_config_dir, (const char* config_path));
DO_API(void, il2cpp_set_data_dir, (const char* data_path));
DO_API(void, il2cpp_set_temp_dir, (const char* temp_path));
DO_API(void, il2cpp_set_commandline_arguments, (int argc, const char* const argv[], const char* basedir));
DO_API(void, il2cpp_set_commandline_arguments_utf16, (int argc, const Il2CppChar* const argv[], const char* basedir));
DO_API(void, il2cpp_set_config_utf16, (const Il2CppChar* executablePath));
DO_API(void, il2cpp_set_config, (const char* executablePath));
DO_API(void, il2cpp_set_memory_callbacks, (Il2CppMemoryCallbacks* callbacks));
DO_API(const Il2CppImage*, il2cpp_get_corlib, ());
DO_API(void, il2cpp_add_internal_call, (const char* name, Il2CppMethodPointer method));
DO_API(Il2CppMethodPointer, il2cpp_resolve_icall, (const char* name));
DO_API(void*, il2cpp_alloc, (size_t size));
DO_API(void, il2cpp_free, (void* ptr));
#pragma endregion
#pragma region Array
DO_API(Il2CppClass*, il2cpp_array_class_get, (Il2CppClass* element_class, uint32_t rank));
DO_API(uint32_t, il2cpp_array_length, (Il2CppArray* array));
DO_API(uint32_t, il2cpp_array_get_byte_length, (Il2CppArray* array));
DO_API(Il2CppArray*, il2cpp_array_new, (Il2CppClass* elementTypeInfo, il2cpp_array_size_t length));
DO_API(Il2CppArray*, il2cpp_array_new_specific, (Il2CppClass* arrayTypeInfo, il2cpp_array_size_t length));
DO_API(Il2CppArray*, il2cpp_array_new_full, (Il2CppClass* array_class, il2cpp_array_size_t* lengths, il2cpp_array_size_t* lower_bounds));
DO_API(Il2CppClass*, il2cpp_bounded_array_class_get, (Il2CppClass* element_class, uint32_t rank, bool bounded));
DO_API(int, il2cpp_array_element_size, (const Il2CppClass* array_class));
#pragma endregion
#pragma region Assembly
DO_API(const Il2CppImage*, il2cpp_assembly_get_image, (const Il2CppAssembly* assembly));
#pragma endregion
#pragma region Class
DO_API(void, il2cpp_class_for_each, (void(*klassReportFunc)(Il2CppClass* klass, void* userData), void* userData));
DO_API(const Il2CppType*, il2cpp_class_enum_basetype, (Il2CppClass* klass));
DO_API(bool, il2cpp_class_is_generic, (const Il2CppClass* klass));
DO_API(bool, il2cpp_class_is_inflated, (const Il2CppClass* klass));
DO_API(bool, il2cpp_class_is_assignable_from, (Il2CppClass* klass, Il2CppClass* oklass));
DO_API(bool, il2cpp_class_is_subclass_of, (Il2CppClass* klass, Il2CppClass* klassc, bool check_interfaces));
DO_API(bool, il2cpp_class_has_parent, (Il2CppClass* klass, Il2CppClass* klassc));
DO_API(Il2CppClass*, il2cpp_class_from_il2cpp_type, (const Il2CppType* type));
DO_API(Il2CppClass*, il2cpp_class_from_name, (const Il2CppImage* image, const char* namespaze, const char* name));
DO_API(Il2CppClass*, il2cpp_class_from_system_type, (Il2CppReflectionType* type));
DO_API(Il2CppClass*, il2cpp_class_get_element_class, (Il2CppClass* klass));
DO_API(const EventInfo*, il2cpp_class_get_events, (Il2CppClass* klass, void** iter));
DO_API(FieldInfo*, il2cpp_class_get_fields, (Il2CppClass* klass, void** iter));
DO_API(Il2CppClass*, il2cpp_class_get_nested_types, (Il2CppClass* klass, void** iter));
DO_API(Il2CppClass*, il2cpp_class_get_interfaces, (Il2CppClass* klass, void** iter));
DO_API(const PropertyInfo*, il2cpp_class_get_properties, (Il2CppClass* klass, void** iter));
DO_API(const PropertyInfo*, il2cpp_class_get_property_from_name, (Il2CppClass* klass, const char* name));
DO_API(FieldInfo*, il2cpp_class_get_field_from_name, (Il2CppClass* klass, const char* name));
DO_API(const MethodInfo*, il2cpp_class_get_methods, (Il2CppClass* klass, void** iter));
DO_API(const MethodInfo*, il2cpp_class_get_method_from_name, (Il2CppClass* klass, const char* name, int argsCount));
DO_API(const char*, il2cpp_class_get_name, (Il2CppClass* klass));
DO_API(void, il2cpp_type_get_name_chunked, (const Il2CppType* type, void(*chunkReportFunc)(void* data, void* userData), void* userData));
DO_API(const char*, il2cpp_class_get_namespace, (Il2CppClass* klass));
DO_API(Il2CppClass*, il2cpp_class_get_parent, (Il2CppClass* klass));
DO_API(Il2CppClass*, il2cpp_class_get_declaring_type, (Il2CppClass* klass));
DO_API(int32_t, il2cpp_class_instance_size, (Il2CppClass* klass));
DO_API(size_t, il2cpp_class_num_fields, (const Il2CppClass* enumKlass));
DO_API(bool, il2cpp_class_is_valuetype, (const Il2CppClass* klass));
DO_API(int32_t, il2cpp_class_value_size, (Il2CppClass* klass, uint32_t* align));
DO_API(bool, il2cpp_class_is_blittable, (const Il2CppClass* klass));
DO_API(int, il2cpp_class_get_flags, (const Il2CppClass* klass));
DO_API(bool, il2cpp_class_is_abstract, (const Il2CppClass* klass));
DO_API(bool, il2cpp_class_is_interface, (const Il2CppClass* klass));
DO_API(int, il2cpp_class_array_element_size, (const Il2CppClass* klass));
DO_API(Il2CppClass*, il2cpp_class_from_type, (const Il2CppType* type));
DO_API(const Il2CppType*, il2cpp_class_get_type, (Il2CppClass* klass));
DO_API(uint32_t, il2cpp_class_get_type_token, (Il2CppClass* klass));
DO_API(bool, il2cpp_class_has_attribute, (Il2CppClass* klass, Il2CppClass* attr_class));
DO_API(bool, il2cpp_class_has_references, (Il2CppClass* klass));
DO_API(bool, il2cpp_class_is_enum, (const Il2CppClass* klass));
DO_API(const Il2CppImage*, il2cpp_class_get_image, (Il2CppClass* klass));
DO_API(const char*, il2cpp_class_get_assemblyname, (const Il2CppClass* klass));
DO_API(int, il2cpp_class_get_rank, (const Il2CppClass* klass));
DO_API(uint32_t, il2cpp_class_get_data_size, (const Il2CppClass* klass));
DO_API(void*, il2cpp_class_get_static_field_data, (const Il2CppClass* klass));
#pragma endregion
#pragma region Stats
DO_API(bool, il2cpp_stats_dump_to_file, (const char* path));
DO_API(uint64_t, il2cpp_stats_get_value, (Il2CppStat stat));
#pragma endregion
#pragma region Domain
DO_API(Il2CppDomain*, il2cpp_domain_get, ());
DO_API(const Il2CppAssembly*, il2cpp_domain_assembly_open, (Il2CppDomain* domain, const char* name));
DO_API(const Il2CppAssembly**, il2cpp_domain_get_assemblies, (const Il2CppDomain* domain, size_t* size));
#pragma endregion
#pragma region Exception
DO_API_NO_RETURN(void, il2cpp_raise_exception, (Il2CppException*));
DO_API(Il2CppException*, il2cpp_exception_from_name_msg, (const Il2CppImage* image, const char* name_space, const char* name, const char* msg));
DO_API(Il2CppException*, il2cpp_get_exception_argument_null, (const char* arg));
DO_API(void, il2cpp_format_exception, (const Il2CppException* ex, char* message, int message_size));
DO_API(void, il2cpp_format_stack_trace, (const Il2CppException* ex, char* output, int output_size));
DO_API(void, il2cpp_unhandled_exception, (Il2CppException*));
#pragma endregion
#pragma region Field
DO_API(int, il2cpp_field_get_flags, (FieldInfo* field));
DO_API(const char*, il2cpp_field_get_name, (FieldInfo* field));
DO_API(Il2CppClass*, il2cpp_field_get_parent, (FieldInfo* field));
DO_API(size_t, il2cpp_field_get_offset, (FieldInfo* field));
DO_API(const Il2CppType*, il2cpp_field_get_type, (FieldInfo* field));
DO_API(void, il2cpp_field_get_value, (Il2CppObject* obj, FieldInfo* field, void* value));
DO_API(Il2CppObject*, il2cpp_field_get_value_object, (FieldInfo* field, Il2CppObject* obj));
DO_API(bool, il2cpp_field_has_attribute, (FieldInfo* field, Il2CppClass* attr_class));
DO_API(void, il2cpp_field_set_value, (Il2CppObject* obj, FieldInfo* field, void* value));
DO_API(void, il2cpp_field_static_get_value, (FieldInfo* field, void* value));
DO_API(void, il2cpp_field_static_set_value, (FieldInfo* field, void* value));
DO_API(void, il2cpp_field_set_value_object, (Il2CppObject* instance, FieldInfo* field, Il2CppObject* value));
DO_API(bool, il2cpp_field_is_literal, (FieldInfo* field));
#pragma endregion
#pragma region GC
DO_API(void, il2cpp_gc_collect, (int maxGenerations));
DO_API(int32_t, il2cpp_gc_collect_a_little, ());
DO_API(void, il2cpp_gc_disable, ());
DO_API(void, il2cpp_gc_enable, ());
DO_API(bool, il2cpp_gc_is_disabled, ());
DO_API(int64_t, il2cpp_gc_get_max_time_slice_ns, ());
DO_API(void, il2cpp_gc_set_max_time_slice_ns, (int64_t maxTimeSlice));
DO_API(bool, il2cpp_gc_is_incremental, ());
DO_API(int64_t, il2cpp_gc_get_used_size, ());
DO_API(int64_t, il2cpp_gc_get_heap_size, ());
DO_API(void, il2cpp_gc_wbarrier_set_field, (Il2CppObject* obj, void** targetAddress, void* object));
DO_API(bool, il2cpp_gc_has_strict_wbarriers, ());
DO_API(void, il2cpp_gc_set_external_allocation_tracker, (void(*func)(void*, size_t, int)));
DO_API(void, il2cpp_gc_set_external_wbarrier_tracker, (void(*func)(void**)));
DO_API(void, il2cpp_gc_foreach_heap, (void(*func)(void* data, void* userData), void* userData));
DO_API(void, il2cpp_stop_gc_world, ());
DO_API(void, il2cpp_start_gc_world, ());
#pragma endregion
#pragma region GCHandle
DO_API(uint32_t, il2cpp_gchandle_new, (Il2CppObject* obj, bool pinned));
DO_API(uint32_t, il2cpp_gchandle_new_weakref, (Il2CppObject* obj, bool track_resurrection));
DO_API(Il2CppObject*, il2cpp_gchandle_get_target, (uint32_t gchandle));
DO_API(void, il2cpp_gchandle_free, (uint32_t gchandle));
DO_API(void, il2cpp_gchandle_foreach_get_target, (void(*func)(void* data, void* userData), void* userData));
#pragma endregion
#pragma region VMRuntimeInfo
DO_API(uint32_t, il2cpp_object_header_size, ());
DO_API(uint32_t, il2cpp_array_object_header_size, ());
DO_API(uint32_t, il2cpp_offset_of_array_length_in_array_object_header, ());
DO_API(uint32_t, il2cpp_offset_of_array_bounds_in_array_object_header, ());
DO_API(uint32_t, il2cpp_allocation_granularity, ());
#pragma endregion
#pragma region Liveness
DO_API(void*, il2cpp_unity_liveness_calculation_begin, (Il2CppClass* filter, int max_object_count, il2cpp_register_object_callback callback, void* userdata, il2cpp_WorldChangedCallback onWorldStarted, il2cpp_WorldChangedCallback onWorldStopped));
DO_API(void, il2cpp_unity_liveness_calculation_end, (void* state));
DO_API(void, il2cpp_unity_liveness_calculation_from_root, (Il2CppObject* root, void* state));
DO_API(void, il2cpp_unity_liveness_calculation_from_statics, (void* state));
#pragma endregion
#pragma region Method
DO_API(const Il2CppType*, il2cpp_method_get_return_type, (const MethodInfo* method));
DO_API(Il2CppClass*, il2cpp_method_get_declaring_type, (const MethodInfo* method));
DO_API(const char*, il2cpp_method_get_name, (const MethodInfo* method));
DO_API(const MethodInfo*, il2cpp_method_get_from_reflection, (const Il2CppReflectionMethod* method));
DO_API(Il2CppReflectionMethod*, il2cpp_method_get_object, (const MethodInfo* method, Il2CppClass* refclass));
DO_API(bool, il2cpp_method_is_generic, (const MethodInfo* method));
DO_API(bool, il2cpp_method_is_inflated, (const MethodInfo* method));
DO_API(bool, il2cpp_method_is_instance, (const MethodInfo* method));
DO_API(uint32_t, il2cpp_method_get_param_count, (const MethodInfo* method));
DO_API(const Il2CppType*, il2cpp_method_get_param, (const MethodInfo* method, uint32_t index));
DO_API(Il2CppClass*, il2cpp_method_get_class, (const MethodInfo* method));
DO_API(bool, il2cpp_method_has_attribute, (const MethodInfo* method, Il2CppClass* attr_class));
DO_API(uint32_t, il2cpp_method_get_flags, (const MethodInfo* method, uint32_t* iflags));
DO_API(uint32_t, il2cpp_method_get_token, (const MethodInfo* method));
DO_API(const char*, il2cpp_method_get_param_name, (const MethodInfo* method, uint32_t index));
#pragma endregion
#pragma region Property
DO_API(uint32_t, il2cpp_property_get_flags, (PropertyInfo* prop));
DO_API(const MethodInfo*, il2cpp_property_get_get_method, (PropertyInfo* prop));
DO_API(const MethodInfo*, il2cpp_property_get_set_method, (PropertyInfo* prop));
DO_API(const char*, il2cpp_property_get_name, (PropertyInfo* prop));
DO_API(Il2CppClass*, il2cpp_property_get_parent, (PropertyInfo* prop));
#pragma endregion
#pragma region Object
DO_API(Il2CppClass*, il2cpp_object_get_class, (Il2CppObject* obj));
DO_API(uint32_t, il2cpp_object_get_size, (Il2CppObject* obj));
DO_API(const MethodInfo*, il2cpp_object_get_virtual_method, (Il2CppObject* obj, const MethodInfo* method));
DO_API(Il2CppObject*, il2cpp_object_new, (const Il2CppClass* klass));
DO_API(void*, il2cpp_object_unbox, (Il2CppObject* obj));
DO_API(Il2CppObject*, il2cpp_value_box, (Il2CppClass* klass, void* data));
#pragma endregion
#pragma region Monitor
DO_API(void, il2cpp_monitor_enter, (Il2CppObject* obj));
DO_API(bool, il2cpp_monitor_try_enter, (Il2CppObject* obj, uint32_t timeout));
DO_API(void, il2cpp_monitor_exit, (Il2CppObject* obj));
DO_API(void, il2cpp_monitor_pulse, (Il2CppObject* obj));
DO_API(void, il2cpp_monitor_pulse_all, (Il2CppObject* obj));
DO_API(void, il2cpp_monitor_wait, (Il2CppObject* obj));
DO_API(bool, il2cpp_monitor_try_wait, (Il2CppObject* obj, uint32_t timeout));
#pragma endregion
#pragma region Runtime
DO_API(Il2CppObject*, il2cpp_runtime_invoke, (const MethodInfo* method, void* obj, void** params, Il2CppException** exc));
DO_API(Il2CppObject*, il2cpp_runtime_invoke_convert_args, (const MethodInfo* method, void* obj, Il2CppObject** params, int paramCount, Il2CppException** exc));
DO_API(void, il2cpp_runtime_class_init, (Il2CppClass* klass));
DO_API(void, il2cpp_runtime_object_init, (Il2CppObject* obj));
DO_API(void, il2cpp_runtime_object_init_exception, (Il2CppObject* obj, Il2CppException** exc));
DO_API(void, il2cpp_runtime_unhandled_exception_policy_set, (Il2CppRuntimeUnhandledExceptionPolicy value));
#pragma endregion
#pragma region String
DO_API(int32_t, il2cpp_string_length, (Il2CppString* str));
DO_API(Il2CppChar*, il2cpp_string_chars, (Il2CppString* str));
DO_API(Il2CppString*, il2cpp_string_new, (const char* str));
DO_API(Il2CppString*, il2cpp_string_new_len, (const char* str, uint32_t length));
DO_API(Il2CppString*, il2cpp_string_new_utf16, (const Il2CppChar* text, int32_t len));
DO_API(Il2CppString*, il2cpp_string_new_wrapper, (const char* str));
DO_API(Il2CppString*, il2cpp_string_intern, (Il2CppString* str));
DO_API(Il2CppString*, il2cpp_string_is_interned, (Il2CppString* str));
#pragma endregion
#pragma region Thread
DO_API(Il2CppThread*, il2cpp_thread_current, ());
DO_API(Il2CppThread*, il2cpp_thread_attach, (Il2CppDomain* domain));
DO_API(void, il2cpp_thread_detach, (Il2CppThread* thread));
DO_API(Il2CppThread**, il2cpp_thread_get_all_attached_threads, (size_t* size));
DO_API(bool, il2cpp_is_vm_thread, (Il2CppThread* thread));
#pragma endregion
#pragma region StackTrace
DO_API(void, il2cpp_current_thread_walk_frame_stack, (Il2CppFrameWalkFunc func, void* user_data));
DO_API(void, il2cpp_thread_walk_frame_stack, (Il2CppThread* thread, Il2CppFrameWalkFunc func, void* user_data));
DO_API(bool, il2cpp_current_thread_get_top_frame, (Il2CppStackFrameInfo* frame));
DO_API(bool, il2cpp_thread_get_top_frame, (Il2CppThread* thread, Il2CppStackFrameInfo* frame));
DO_API(bool, il2cpp_current_thread_get_frame_at, (int32_t offset, Il2CppStackFrameInfo* frame));
DO_API(bool, il2cpp_thread_get_frame_at, (Il2CppThread* thread, int32_t offset, Il2CppStackFrameInfo* frame));
DO_API(int32_t, il2cpp_current_thread_get_stack_depth, ());
DO_API(int32_t, il2cpp_thread_get_stack_depth, (Il2CppThread* thread));
DO_API(void, il2cpp_override_stack_backtrace, (Il2CppBacktraceFunc stackBacktraceFunc));
#pragma endregion
#pragma region Type
DO_API(Il2CppObject*, il2cpp_type_get_object, (const Il2CppType* type));
DO_API(int, il2cpp_type_get_type, (const Il2CppType* type));
DO_API(Il2CppClass*, il2cpp_type_get_class_or_element_class, (const Il2CppType* type));
DO_API(char*, il2cpp_type_get_name, (const Il2CppType* type));
DO_API(bool, il2cpp_type_is_byref, (const Il2CppType* type));
DO_API(uint32_t, il2cpp_type_get_attrs, (const Il2CppType* type));
DO_API(bool, il2cpp_type_equals, (const Il2CppType* type, const Il2CppType* otherType));
DO_API(char*, il2cpp_type_get_assembly_qualified_name, (const Il2CppType* type));
DO_API(bool, il2cpp_type_is_static, (const Il2CppType* type));
DO_API(bool, il2cpp_type_is_pointer_type, (const Il2CppType* type));
#pragma endregion
#pragma region Image
DO_API(const Il2CppAssembly*, il2cpp_image_get_assembly, (const Il2CppImage* image));
DO_API(const char*, il2cpp_image_get_name, (const Il2CppImage* image));
DO_API(const char*, il2cpp_image_get_filename, (const Il2CppImage* image));
DO_API(const MethodInfo*, il2cpp_image_get_entry_point, (const Il2CppImage* image));
DO_API(size_t, il2cpp_image_get_class_count, (const Il2CppImage* image));
DO_API(const Il2CppClass*, il2cpp_image_get_class, (const Il2CppImage* image, size_t index));
#pragma endregion
#pragma region MemoryInformation
DO_API(Il2CppManagedMemorySnapshot*, il2cpp_capture_memory_snapshot, ());
DO_API(void, il2cpp_free_captured_memory_snapshot, (Il2CppManagedMemorySnapshot* snapshot));
DO_API(void, il2cpp_set_find_plugin_callback, (Il2CppSetFindPlugInCallback method));
#pragma endregion
#pragma region Logging
DO_API(void, il2cpp_register_log_callback, (Il2CppLogCallback method));
#pragma endregion
#pragma region Debugger
DO_API(void, il2cpp_debugger_set_agent_options, (const char* options));
DO_API(bool, il2cpp_is_debugger_attached, ());
DO_API(void, il2cpp_register_debugger_agent_transport, (Il2CppDebuggerTransport* debuggerTransport));
#pragma endregion
#pragma region DebugMetadata
DO_API(bool, il2cpp_debug_get_method_info, (const MethodInfo*, Il2CppMethodDebugInfo* methodDebugInfo));
#pragma endregion
#pragma region TLSModule
DO_API(void, il2cpp_unity_install_unitytls_interface, (const void* unitytlsInterfaceStruct));
#pragma endregion
#pragma region CustomAttributes
DO_API(Il2CppCustomAttrInfo*, il2cpp_custom_attrs_from_class, (Il2CppClass* klass));
DO_API(Il2CppCustomAttrInfo*, il2cpp_custom_attrs_from_method, (const MethodInfo* method));
DO_API(Il2CppObject*, il2cpp_custom_attrs_get_attr, (Il2CppCustomAttrInfo* ainfo, Il2CppClass* attr_klass));
DO_API(bool, il2cpp_custom_attrs_has_attr, (Il2CppCustomAttrInfo* ainfo, Il2CppClass* attr_klass));
DO_API(Il2CppArray*, il2cpp_custom_attrs_construct, (Il2CppCustomAttrInfo* cinfo));
DO_API(void, il2cpp_custom_attrs_free, (Il2CppCustomAttrInfo* ainfo));
#pragma endregion
#pragma region Il2CppClassUserDataForGetComponentOptimization
DO_API(int, il2cpp_class_get_userdata_offset, ());
DO_API(void, il2cpp_class_set_userdata, (Il2CppClass* klass, void* userdata));
DO_API(void, il2cpp_set_default_thread_affinity, (int64_t affinity_mask));
#pragma endregion
DO_API(0x02974550, 0x02970540, uint32_t, il2cpp_gchandle_new, (Il2CppObject* obj, bool pinned));
DO_API(0x02974260, 0x02970250, Il2CppObject*, il2cpp_gchandle_get_target, (uint32_t gchandle));
DO_API(0x028BF7E0, 0x028BBE80, Il2CppString*, il2cpp_string_new, (const char* str));

View File

@@ -2,7 +2,7 @@
#include "il2cpp-types.h"
// IL2CPP APIs
#define DO_API(r, n, p) extern r (*n) p
#define DO_API(ca, oa, r, n, p) extern r (*n) p
#include "il2cpp-api-functions.h"
#undef DO_API

View File

@@ -4,24 +4,31 @@ using namespace Genshin;
// N: System.Convert$ToBase64String
// L: mscorlib
DO_APP_FUNC(0x051CC420, 0x051CCB00, Il2CppString*, ToBase64String, (ByteArray* value, int offset, int length, void* method));
// S: Ref/E8 ?? ?? ?? ?? 48 8B D8 EB 23 E8
DO_APP_FUNC(0x086B86C0, 0x086B6440, Il2CppString*, ToBase64String, (ByteArray* value, int offset, int length, void* method));
// N: MoleMole.MonoLoginMainPage.version$set
// L: Assembly-CSharp
DO_APP_FUNC(0X01E6CC80, 0x01E6CD90, void, SetVersion, (void* obj, Il2CppString* value, void* method));
// S: 84 C0 74 35 B9 52 FA 00 00 E8 ?? ?? ?? ?? 84 C0 74 27 B9 52 FA 00 00 E8 ?? ?? ?? ?? 48 85 C0 74 52 4C 8B C7 48 8B D3 48 8B C8 48 8B 5C 24 30 48 83 C4 20 5F E9
DO_APP_FUNC(0X04186660, 0x04180EC0, void, SetVersion, (void* obj, Il2CppString* value, void* method));
// N: UnityEngine.Application$RecordUserData
// L: UnityEngine.CoreModule
DO_APP_FUNC(0x05AFD640, 0x05AFD630, ByteArray*, RecordUserData, (int32_t nType, void* method));
DO_APP_FUNC(0x090BEBC0, 0x090BD710, ByteArray*, RecordUserData, (int32_t nType, void* method));
// N: MoleMole.Packet$XorEncrypt [Obfuscated]
// L: Assembly-CSharp
DO_APP_FUNC(0x0133C8A0, 0x0133D110, void, XorEncrypt, (ByteArray** data, int length, void* method));
DO_APP_FUNC(0x0423B270, 0x04235CE0, void, XorEncrypt, (ByteArray** data, int length, void* method));
// N: Kcp.KcpNative$kcp_client_send_packet [Obfuscated]
// L: Assembly-CSharp
DO_APP_FUNC(0x0094FBD0, 0x0094FCF0, int, KcpSend, (void* client, KcpPacket* pkt, void* method));
DO_APP_FUNC(0x042281D0, 0x04222A60, int, KcpSend, (void* client, KcpPacket* pkt, void* method));
// N: MoleMole.KcpClient$TryDequeueEvent [Obfuscated]
// L: Assembly-CSharp
DO_APP_FUNC(0x026C8690, 0x026C9030, bool, KcpRecv, (void* client, ClientKcpEvent* evt, void* method));
// S: Ref/public static extern Int32 [A-Z]{11}\(IntPtr [A-Z]{11}, [A-Z]{11}& [A-Z]{11}\)
DO_APP_FUNC(0x02BAFFF0, 0x02BAC3D0, bool, KcpRecv, (void* client, ClientKcpEvent* evt, void* method));
DO_APP_FUNC(0x08A43710, 0x08A41130, LPVOID, GetDefaultEncoding, (void* method));
DO_APP_FUNC(0x08A42FB0, 0x08A409B0, Il2CppString*, GetString, (LPVOID encoding, LPVOID bytes, void* method));

View File

@@ -2,7 +2,7 @@
#include "il2cpp-init.h"
#define DO_API(r, n, p) r (*n) p
#define DO_API(ca, oa, r, n, p) r (*n) p
#include "il2cpp-api-functions.h"
#undef DO_API
@@ -20,11 +20,6 @@ namespace Genshin {
using std::string;
UINT64 GetAddressByExports(HMODULE base, const char* name) {
UINT64 funcAddr = reinterpret_cast<UINT64>(GetProcAddress(base, name));
return funcAddr == 0 ? 0 : funcAddr;
}
void InitIL2CPP() {
TCHAR szFileName[MAX_PATH];
GetModuleFileName(NULL, szFileName, MAX_PATH);
@@ -32,7 +27,7 @@ void InitIL2CPP() {
auto hBase = GetModuleHandle("UserAssembly.dll");
auto bAddr = (UINT64)hBase;
auto cAddr = (UINT64)GetModuleHandle("UnityPlayer.dll");
#define DO_API(r, n, p) n = (r (*) p) GetAddressByExports(hBase, #n);
#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))

View File

@@ -1,3 +1,3 @@
using namespace Genshin;
DO_UNI_FUNC(0x00BAB2B0, 0x00BAB2B0, ByteArray*, UnityEngine_RecordUserData, (int32_t nType));
DO_UNI_FUNC(0x00100300, 0x00100300, ByteArray*, UnityEngine_RecordUserData, (int32_t nType));

View File

@@ -1,6 +1,17 @@
#include "pch.h"
#include "util.h"
VOID DisableVMProtect() {
DWORD oldProtect = 0;
auto ntdll = GetModuleHandleA("ntdll.dll");
BYTE callcode = ((BYTE*)GetProcAddress(ntdll, "NtQuerySection"))[4] - 1;
BYTE restore[] = { 0x4C, 0x8B, 0xD1, 0xB8, callcode };
auto nt_vp = (BYTE*)GetProcAddress(ntdll, "NtProtectVirtualMemory");
VirtualProtect(nt_vp, sizeof(restore), PAGE_EXECUTE_READWRITE, &oldProtect);
memcpy(nt_vp, restore, sizeof(restore));
VirtualProtect(nt_vp, sizeof(restore), oldProtect, &oldProtect);
}
#pragma region StringConvert
string IlStringToString(Il2CppString* str, UINT codePage) {

View File

@@ -2,6 +2,7 @@
using std::string;
VOID DisableVMProtect();
bool IsLittleEndian();
HWND FindMainWindowByPID(DWORD pid);
UINT32 GCHandle_New(LPVOID object, bool pinned);

41
res/App.Designer.cs generated
View File

@@ -18,7 +18,7 @@ namespace YaeAchievement.res {
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class App {
@@ -219,6 +219,15 @@ namespace YaeAchievement.res {
}
}
/// <summary>
/// Looks up a localized string similar to Please update genshin and retry..
/// </summary>
internal static string GenshinHashError {
get {
return ResourceManager.GetString("GenshinHashError", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Please close game before run this application. ({0}).
/// </summary>
@@ -246,15 +255,6 @@ namespace YaeAchievement.res {
}
}
/// <summary>
/// Looks up a localized string similar to To fetch new data, Restart the application after delete cache\d1a8ef40a67a5929.miko..
/// </summary>
internal static string RefreshData {
get {
return ResourceManager.GetString("RefreshData", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Reward not taken.
/// </summary>
@@ -301,15 +301,6 @@ namespace YaeAchievement.res {
}
}
/// <summary>
/// Looks up a localized string similar to Unzip the package to update application..
/// </summary>
internal static string UpdateDownloadFinish {
get {
return ResourceManager.GetString("UpdateDownloadFinish", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Downloading update package....
/// </summary>
@@ -328,6 +319,16 @@ namespace YaeAchievement.res {
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] Updater {
get {
object obj = ResourceManager.GetObject("Updater", resourceCulture);
return ((byte[])(obj));
}
}
/// <summary>
/// Looks up a localized string similar to Upload error to appcenter....
/// </summary>
@@ -338,7 +339,7 @@ namespace YaeAchievement.res {
}
/// <summary>
/// Looks up a localized string similar to Use previous fetched data..
/// Looks up a localized string similar to Use previous fetched data? (yes|no).
/// </summary>
internal static string UsePreviousData {
get {

View File

@@ -101,17 +101,11 @@ Input a number (0-5): </value>
<data name="UpdateDownloading" xml:space="preserve">
<value>Downloading update package...</value>
</data>
<data name="UpdateDownloadFinish" xml:space="preserve">
<value>Unzip the package to update application.</value>
</data>
<data name="AppBanner" xml:space="preserve">
<value>YaeAchievement ({0})</value>
</data>
<data name="UsePreviousData" xml:space="preserve">
<value>Use previous fetched data.</value>
</data>
<data name="RefreshData" xml:space="preserve">
<value>To fetch new data, Restart the application after delete cache\d1a8ef40a67a5929.miko.</value>
<value>Use previous fetched data? (yes|no)</value>
</data>
<data name="NetworkError" xml:space="preserve">
<value>Network error:</value>
@@ -125,4 +119,11 @@ Input a number (0-5): </value>
<data name="ExceptionNetwork" xml:space="preserve">
<value>Network error ({0}: {1})</value>
</data>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="Updater" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Updater.exe;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="GenshinHashError" xml:space="preserve">
<value>Please update genshin and retry.</value>
</data>
</root>

View File

@@ -35,10 +35,10 @@
<value>在小程序导入页面输入以下代码: {0}</value>
</data>
<data name="ExportToSnapGenshinSuccess" xml:space="preserve">
<value>在 SnapGenshin 进行下一步操作</value>
<value>在 SnapHutao 进行下一步操作</value>
</data>
<data name="ExportToSnapGenshinNeedUpdate" xml:space="preserve">
<value>更新 SnapGenshin 至最新版本后重试</value>
<value>更新 SnapHutao 至最新版本后重试</value>
</data>
<data name="ExportToFileSuccess" xml:space="preserve">
<value>成就数据已导出至 {0}</value>
@@ -95,17 +95,11 @@
<data name="UpdateDownloading" xml:space="preserve">
<value>正在下载更新包...</value>
</data>
<data name="UpdateDownloadFinish" xml:space="preserve">
<value>关闭程序后, 将压缩包解压至当前目录即可完成更新.</value>
</data>
<data name="AppBanner" xml:space="preserve">
<value>YaeAchievement - 原神成就导出工具 ({0})</value>
</data>
<data name="UsePreviousData" xml:space="preserve">
<value>使用上一次获取到的成就数据</value>
</data>
<data name="RefreshData" xml:space="preserve">
<value>要重新获取数据,手动删除 cache\d1a8ef40a67a5929.miko 后重新启动 YaeAchievement</value>
<value>使用上一次获取到的成就数据吗? (yes|no)</value>
</data>
<data name="NetworkError" xml:space="preserve">
<value>网络错误: {0}</value>
@@ -119,4 +113,7 @@
<data name="ExceptionNetwork" xml:space="preserve">
<value>网络错误,请检查网络后重试 ({0}: {1})</value>
</data>
<data name="GenshinHashError" xml:space="preserve">
<value>请将原神更新至最新版本后重试</value>
</data>
</root>

BIN
res/Updater.exe Normal file

Binary file not shown.

View File

@@ -46,7 +46,12 @@ public static class AppConfig {
if (!File.Exists(path)) {
return null;
}
var content = File.ReadAllText(path);
var copiedLogFilePath = Path.GetTempFileName();
File.Copy(path, copiedLogFilePath, true);
var content = File.ReadAllText(copiedLogFilePath);
try {
File.Delete(copiedLogFilePath);
} catch (Exception) { /* ignore */}
var matchResult = Regex.Match(content, @"(?m).:/.+(GenshinImpact_Data|YuanShen_Data)");
if (!matchResult.Success) {
return null;

View File

@@ -11,8 +11,7 @@ public class CacheFile {
public DateTime LastWriteTime => Exists() ? File.GetLastWriteTimeUtc(_cacheName) : DateTime.UnixEpoch;
public CacheFile(string identifier) {
Directory.CreateDirectory(Path.Combine(GlobalVars.AppPath, "cache"));
_cacheName = Path.Combine(GlobalVars.AppPath, $"cache/{identifier.MD5Hash()[..16]}.miko");
_cacheName = Path.Combine(GlobalVars.CachePath, $"{identifier.MD5Hash()[..16]}.miko");
}
public bool Exists() => File.Exists(_cacheName);

View File

@@ -44,7 +44,7 @@ public static class Export {
RequestUri = new Uri($"https://77.cocogoat.work/v1/memo?source={App.AllAchievement}"),
Content = new StringContent(result, Encoding.UTF8, "application/json")
};
using var response = Utils.CHttpClient.Value.Send(request);
using var response = Utils.CHttpClient.Send(request);
if (response.StatusCode != HttpStatusCode.Created) {
Console.WriteLine(App.ExportToCocogoatFail);
return;
@@ -67,7 +67,7 @@ public static class Export {
RequestUri = new Uri("https://api.qyinter.com/achievementRedis"),
Content = new StringContent(result, Encoding.UTF8, "application/json")
};
using var response = Utils.CHttpClient.Value.Send(request);
using var response = Utils.CHttpClient.Send(request);
Console.WriteLine(App.ExportToWxApp1Success, id);
}

View File

@@ -5,21 +5,29 @@ namespace YaeAchievement;
// ReSharper disable InconsistentNaming
// ReSharper disable ConvertToConstant.Global
// ReSharper disable FieldCanBeMadeReadOnly.Global
// ReSharper disable once MemberCanBePrivate.Global
public static class GlobalVars {
public static bool DebugProxy => false;
public static bool UnexpectedExit { get; set; }= true;
public static bool UnexpectedExit { get; set; } = true;
public static bool PauseOnExit { get; set; } = true;
public static Version AppVersion { get; } = Assembly.GetEntryAssembly()!.GetName().Version!;
private static readonly string DataDir = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
public static readonly string LibPath = Path.Combine(DataDir, "YaeAchievement.dll");
public static readonly string AppPath = AppDomain.CurrentDomain.BaseDirectory;
private static readonly string CommonData = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
public static readonly string DataPath = Path.Combine(CommonData, "Yae");
public static readonly string CachePath = Path.Combine(DataPath, "cache");
public static readonly string LibFilePath = Path.Combine(DataPath, "YaeAchievement.dll");
public const uint AppVersionCode = 30;
public const string AppVersionName = "2.2";
public const uint AppVersionCode = 34;
public const string AppVersionName = "2.4.1";
public const string PipeName = "YaeAchievementPipe";
public const string BucketHost = "https://cn-cd-1259389942.file.myqcloud.com";
static GlobalVars() {
Directory.CreateDirectory(DataPath);
Directory.CreateDirectory(CachePath);
}
}

View File

@@ -28,11 +28,22 @@ new EventLog("AppInit") {
{ "SystemVersion", DeviceHelper.GetSystemVersion() }
}
}.Enqueue();
var usePreviousData = false;
var historyCache = new CacheFile("ExportData");
if (historyCache.LastWriteTime.AddMinutes(10) > DateTime.UtcNow) {
Console.WriteLine(App.UsePreviousData);
Console.WriteLine(App.RefreshData);
Export.Choose(AchievementAllDataNotify.Parser.ParseFrom(historyCache.Read().Content));
usePreviousData = Console.ReadLine() == "yes";
}
Export:
if(usePreviousData) {
AchievementAllDataNotify data;
try {
data = AchievementAllDataNotify.Parser.ParseFrom(historyCache.Read().Content);
} catch (Exception) {
usePreviousData = false;
goto Export;
}
Export.Choose(data);
} else {
StartAndWaitResult(AppConfig.GamePath, str => {
GlobalVars.UnexpectedExit = false;

View File

@@ -22,18 +22,19 @@ public static partial class AchievementAllDataNotifyReflection {
static AchievementAllDataNotifyReflection() {
byte[] descriptorData = global::System.Convert.FromBase64String(
string.Concat(
"Ch5BY2hpZXZlbWVudEFsbERhdGFOb3RpZnkucHJvdG8iowIKGEFjaGlldmVt",
"ZW50QWxsRGF0YU5vdGlmeRIzCgRsaXN0GAQgAygLMiUuQWNoaWV2ZW1lbnRB",
"bGxEYXRhTm90aWZ5LkFjaGlldmVtZW50GtEBCgtBY2hpZXZlbWVudBIKCgJp",
"ZBgOIAEoDRI8CgZzdGF0dXMYDSABKA4yLC5BY2hpZXZlbWVudEFsbERhdGFO",
"b3RpZnkuQWNoaWV2ZW1lbnQuU3RhdHVzEg8KB2N1cnJlbnQYDCABKA0SDQoF",
"dG90YWwYCCABKA0SEQoJdGltZXN0YW1wGAsgASgNIkUKBlN0YXR1cxILCgdJ",
"TlZBTElEEAASDgoKVU5GSU5JU0hFRBABEgwKCEZJTklTSEVEEAISEAoMUkVX",
"QVJEX1RBS0VOEANiBnByb3RvMw=="));
"Ch5BY2hpZXZlbWVudEFsbERhdGFOb3RpZnkucHJvdG8ivwIKGEFjaGlldmVt",
"ZW50QWxsRGF0YU5vdGlmeRIzCgRsaXN0GAggAygLMiUuQWNoaWV2ZW1lbnRB",
"bGxEYXRhTm90aWZ5LkFjaGlldmVtZW50Gu0BCgtBY2hpZXZlbWVudBIRCgl0",
"aW1lc3RhbXAYCCABKA0SDwoHY3VycmVudBgLIAEoDRINCgV0b3RhbBgGIAEo",
"DRIKCgJpZBgOIAEoDRI8CgZzdGF0dXMYDyABKA4yLC5BY2hpZXZlbWVudEFs",
"bERhdGFOb3RpZnkuQWNoaWV2ZW1lbnQuU3RhdHVzImEKBlN0YXR1cxISCg5T",
"VEFUVVNfSU5WQUxJRBAAEhUKEVNUQVRVU19VTkZJTklTSEVEEAESEwoPU1RB",
"VFVTX0ZJTklTSEVEEAISFwoTU1RBVFVTX1JFV0FSRF9UQUtFThADYgZwcm90",
"bzM="));
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
new pbr::FileDescriptor[] { },
new pbr::GeneratedClrTypeInfo(null, null, new pbr::GeneratedClrTypeInfo[] {
new pbr::GeneratedClrTypeInfo(typeof(global::AchievementAllDataNotify), global::AchievementAllDataNotify.Parser, new[]{ "List" }, null, null, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::AchievementAllDataNotify.Types.Achievement), global::AchievementAllDataNotify.Types.Achievement.Parser, new[]{ "Id", "Status", "Current", "Total", "Timestamp" }, null, new[]{ typeof(global::AchievementAllDataNotify.Types.Achievement.Types.Status) }, null, null)})
new pbr::GeneratedClrTypeInfo(typeof(global::AchievementAllDataNotify), global::AchievementAllDataNotify.Parser, new[]{ "List" }, null, null, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::AchievementAllDataNotify.Types.Achievement), global::AchievementAllDataNotify.Types.Achievement.Parser, new[]{ "Timestamp", "Current", "Total", "Id", "Status" }, null, new[]{ typeof(global::AchievementAllDataNotify.Types.Achievement.Types.Status) }, null, null)})
}));
}
#endregion
@@ -85,9 +86,9 @@ public sealed partial class AchievementAllDataNotify : pb::IMessage<AchievementA
}
/// <summary>Field number for the "list" field.</summary>
public const int ListFieldNumber = 4;
public const int ListFieldNumber = 8;
private static readonly pb::FieldCodec<global::AchievementAllDataNotify.Types.Achievement> _repeated_list_codec
= pb::FieldCodec.ForMessage(34, global::AchievementAllDataNotify.Types.Achievement.Parser);
= pb::FieldCodec.ForMessage(66, global::AchievementAllDataNotify.Types.Achievement.Parser);
private readonly pbc::RepeatedField<global::AchievementAllDataNotify.Types.Achievement> list_ = new pbc::RepeatedField<global::AchievementAllDataNotify.Types.Achievement>();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
@@ -188,7 +189,7 @@ public sealed partial class AchievementAllDataNotify : pb::IMessage<AchievementA
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
break;
case 34: {
case 66: {
list_.AddEntriesFrom(input, _repeated_list_codec);
break;
}
@@ -207,7 +208,7 @@ public sealed partial class AchievementAllDataNotify : pb::IMessage<AchievementA
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input);
break;
case 34: {
case 66: {
list_.AddEntriesFrom(ref input, _repeated_list_codec);
break;
}
@@ -255,11 +256,11 @@ public sealed partial class AchievementAllDataNotify : pb::IMessage<AchievementA
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public Achievement(Achievement other) : this() {
id_ = other.id_;
status_ = other.status_;
timestamp_ = other.timestamp_;
current_ = other.current_;
total_ = other.total_;
timestamp_ = other.timestamp_;
id_ = other.id_;
status_ = other.status_;
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
}
@@ -269,6 +270,42 @@ public sealed partial class AchievementAllDataNotify : pb::IMessage<AchievementA
return new Achievement(this);
}
/// <summary>Field number for the "timestamp" field.</summary>
public const int TimestampFieldNumber = 8;
private uint timestamp_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public uint Timestamp {
get { return timestamp_; }
set {
timestamp_ = value;
}
}
/// <summary>Field number for the "current" field.</summary>
public const int CurrentFieldNumber = 11;
private uint current_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public uint Current {
get { return current_; }
set {
current_ = value;
}
}
/// <summary>Field number for the "total" field.</summary>
public const int TotalFieldNumber = 6;
private uint total_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public uint Total {
get { return total_; }
set {
total_ = value;
}
}
/// <summary>Field number for the "id" field.</summary>
public const int IdFieldNumber = 14;
private uint id_;
@@ -282,7 +319,7 @@ public sealed partial class AchievementAllDataNotify : pb::IMessage<AchievementA
}
/// <summary>Field number for the "status" field.</summary>
public const int StatusFieldNumber = 13;
public const int StatusFieldNumber = 15;
private global::AchievementAllDataNotify.Types.Achievement.Types.Status status_ = global::AchievementAllDataNotify.Types.Achievement.Types.Status.Invalid;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
@@ -293,42 +330,6 @@ public sealed partial class AchievementAllDataNotify : pb::IMessage<AchievementA
}
}
/// <summary>Field number for the "current" field.</summary>
public const int CurrentFieldNumber = 12;
private uint current_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public uint Current {
get { return current_; }
set {
current_ = value;
}
}
/// <summary>Field number for the "total" field.</summary>
public const int TotalFieldNumber = 8;
private uint total_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public uint Total {
get { return total_; }
set {
total_ = value;
}
}
/// <summary>Field number for the "timestamp" field.</summary>
public const int TimestampFieldNumber = 11;
private uint timestamp_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public uint Timestamp {
get { return timestamp_; }
set {
timestamp_ = value;
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public override bool Equals(object other) {
@@ -344,11 +345,11 @@ public sealed partial class AchievementAllDataNotify : pb::IMessage<AchievementA
if (ReferenceEquals(other, this)) {
return true;
}
if (Id != other.Id) return false;
if (Status != other.Status) return false;
if (Timestamp != other.Timestamp) return false;
if (Current != other.Current) return false;
if (Total != other.Total) return false;
if (Timestamp != other.Timestamp) return false;
if (Id != other.Id) return false;
if (Status != other.Status) return false;
return Equals(_unknownFields, other._unknownFields);
}
@@ -356,11 +357,11 @@ public sealed partial class AchievementAllDataNotify : pb::IMessage<AchievementA
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public override int GetHashCode() {
int hash = 1;
if (Id != 0) hash ^= Id.GetHashCode();
if (Status != global::AchievementAllDataNotify.Types.Achievement.Types.Status.Invalid) hash ^= Status.GetHashCode();
if (Timestamp != 0) hash ^= Timestamp.GetHashCode();
if (Current != 0) hash ^= Current.GetHashCode();
if (Total != 0) hash ^= Total.GetHashCode();
if (Timestamp != 0) hash ^= Timestamp.GetHashCode();
if (Id != 0) hash ^= Id.GetHashCode();
if (Status != global::AchievementAllDataNotify.Types.Achievement.Types.Status.Invalid) hash ^= Status.GetHashCode();
if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode();
}
@@ -380,25 +381,25 @@ public sealed partial class AchievementAllDataNotify : pb::IMessage<AchievementA
output.WriteRawMessage(this);
#else
if (Total != 0) {
output.WriteRawTag(64);
output.WriteRawTag(48);
output.WriteUInt32(Total);
}
if (Timestamp != 0) {
output.WriteRawTag(88);
output.WriteRawTag(64);
output.WriteUInt32(Timestamp);
}
if (Current != 0) {
output.WriteRawTag(96);
output.WriteRawTag(88);
output.WriteUInt32(Current);
}
if (Status != global::AchievementAllDataNotify.Types.Achievement.Types.Status.Invalid) {
output.WriteRawTag(104);
output.WriteEnum((int) Status);
}
if (Id != 0) {
output.WriteRawTag(112);
output.WriteUInt32(Id);
}
if (Status != global::AchievementAllDataNotify.Types.Achievement.Types.Status.Invalid) {
output.WriteRawTag(120);
output.WriteEnum((int) Status);
}
if (_unknownFields != null) {
_unknownFields.WriteTo(output);
}
@@ -410,25 +411,25 @@ public sealed partial class AchievementAllDataNotify : pb::IMessage<AchievementA
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) {
if (Total != 0) {
output.WriteRawTag(64);
output.WriteRawTag(48);
output.WriteUInt32(Total);
}
if (Timestamp != 0) {
output.WriteRawTag(88);
output.WriteRawTag(64);
output.WriteUInt32(Timestamp);
}
if (Current != 0) {
output.WriteRawTag(96);
output.WriteRawTag(88);
output.WriteUInt32(Current);
}
if (Status != global::AchievementAllDataNotify.Types.Achievement.Types.Status.Invalid) {
output.WriteRawTag(104);
output.WriteEnum((int) Status);
}
if (Id != 0) {
output.WriteRawTag(112);
output.WriteUInt32(Id);
}
if (Status != global::AchievementAllDataNotify.Types.Achievement.Types.Status.Invalid) {
output.WriteRawTag(120);
output.WriteEnum((int) Status);
}
if (_unknownFields != null) {
_unknownFields.WriteTo(ref output);
}
@@ -439,11 +440,8 @@ public sealed partial class AchievementAllDataNotify : pb::IMessage<AchievementA
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public int CalculateSize() {
int size = 0;
if (Id != 0) {
size += 1 + pb::CodedOutputStream.ComputeUInt32Size(Id);
}
if (Status != global::AchievementAllDataNotify.Types.Achievement.Types.Status.Invalid) {
size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Status);
if (Timestamp != 0) {
size += 1 + pb::CodedOutputStream.ComputeUInt32Size(Timestamp);
}
if (Current != 0) {
size += 1 + pb::CodedOutputStream.ComputeUInt32Size(Current);
@@ -451,8 +449,11 @@ public sealed partial class AchievementAllDataNotify : pb::IMessage<AchievementA
if (Total != 0) {
size += 1 + pb::CodedOutputStream.ComputeUInt32Size(Total);
}
if (Timestamp != 0) {
size += 1 + pb::CodedOutputStream.ComputeUInt32Size(Timestamp);
if (Id != 0) {
size += 1 + pb::CodedOutputStream.ComputeUInt32Size(Id);
}
if (Status != global::AchievementAllDataNotify.Types.Achievement.Types.Status.Invalid) {
size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Status);
}
if (_unknownFields != null) {
size += _unknownFields.CalculateSize();
@@ -466,11 +467,8 @@ public sealed partial class AchievementAllDataNotify : pb::IMessage<AchievementA
if (other == null) {
return;
}
if (other.Id != 0) {
Id = other.Id;
}
if (other.Status != global::AchievementAllDataNotify.Types.Achievement.Types.Status.Invalid) {
Status = other.Status;
if (other.Timestamp != 0) {
Timestamp = other.Timestamp;
}
if (other.Current != 0) {
Current = other.Current;
@@ -478,8 +476,11 @@ public sealed partial class AchievementAllDataNotify : pb::IMessage<AchievementA
if (other.Total != 0) {
Total = other.Total;
}
if (other.Timestamp != 0) {
Timestamp = other.Timestamp;
if (other.Id != 0) {
Id = other.Id;
}
if (other.Status != global::AchievementAllDataNotify.Types.Achievement.Types.Status.Invalid) {
Status = other.Status;
}
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
@@ -496,26 +497,26 @@ public sealed partial class AchievementAllDataNotify : pb::IMessage<AchievementA
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
break;
case 64: {
case 48: {
Total = input.ReadUInt32();
break;
}
case 88: {
case 64: {
Timestamp = input.ReadUInt32();
break;
}
case 96: {
case 88: {
Current = input.ReadUInt32();
break;
}
case 104: {
Status = (global::AchievementAllDataNotify.Types.Achievement.Types.Status) input.ReadEnum();
break;
}
case 112: {
Id = input.ReadUInt32();
break;
}
case 120: {
Status = (global::AchievementAllDataNotify.Types.Achievement.Types.Status) input.ReadEnum();
break;
}
}
}
#endif
@@ -531,26 +532,26 @@ public sealed partial class AchievementAllDataNotify : pb::IMessage<AchievementA
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input);
break;
case 64: {
case 48: {
Total = input.ReadUInt32();
break;
}
case 88: {
case 64: {
Timestamp = input.ReadUInt32();
break;
}
case 96: {
case 88: {
Current = input.ReadUInt32();
break;
}
case 104: {
Status = (global::AchievementAllDataNotify.Types.Achievement.Types.Status) input.ReadEnum();
break;
}
case 112: {
Id = input.ReadUInt32();
break;
}
case 120: {
Status = (global::AchievementAllDataNotify.Types.Achievement.Types.Status) input.ReadEnum();
break;
}
}
}
}
@@ -562,10 +563,10 @@ public sealed partial class AchievementAllDataNotify : pb::IMessage<AchievementA
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public static partial class Types {
public enum Status {
[pbr::OriginalName("INVALID")] Invalid = 0,
[pbr::OriginalName("UNFINISHED")] Unfinished = 1,
[pbr::OriginalName("FINISHED")] Finished = 2,
[pbr::OriginalName("REWARD_TAKEN")] RewardTaken = 3,
[pbr::OriginalName("STATUS_INVALID")] Invalid = 0,
[pbr::OriginalName("STATUS_UNFINISHED")] Unfinished = 1,
[pbr::OriginalName("STATUS_FINISHED")] Finished = 2,
[pbr::OriginalName("STATUS_REWARD_TAKEN")] RewardTaken = 3,
}
}

View File

@@ -14,19 +14,16 @@ namespace YaeAchievement;
public static class Utils {
public static readonly Lazy<HttpClient> CHttpClient = new (() => {
var c = new HttpClient(new HttpClientHandler {
Proxy = GlobalVars.DebugProxy ? new WebProxy("http://127.0.0.1:8888") : null,
AutomaticDecompression = DecompressionMethods.Brotli | DecompressionMethods.GZip
}) {
DefaultRequestHeaders = {
UserAgent = {
new ProductInfoHeaderValue("YaeAchievement", GlobalVars.AppVersion.ToString(2))
}
public static readonly HttpClient CHttpClient = new (new HttpClientHandler {
Proxy = GlobalVars.DebugProxy ? new WebProxy("http://127.0.0.1:8888") : null,
AutomaticDecompression = DecompressionMethods.Brotli | DecompressionMethods.GZip
}) {
DefaultRequestHeaders = {
UserAgent = {
new ProductInfoHeaderValue("YaeAchievement", GlobalVars.AppVersion.ToString(2))
}
};
return c;
});
}
};
public static byte[] GetBucketFileAsByteArray(string path, bool cache = true) {
try {
@@ -38,7 +35,7 @@ public static class Utils {
if (cache && cacheFile.Exists()) {
msg.Headers.TryAddWithoutValidation("If-None-Match", $"{cacheFile.Read().Etag}");
}
using var response = CHttpClient.Value.Send(msg);
using var response = CHttpClient.Send(msg);
if (cache && response.StatusCode == HttpStatusCode.NotModified) {
return cacheFile.Read().Content.ToByteArray();
}
@@ -90,10 +87,16 @@ public static class Utils {
Console.WriteLine(App.UpdateDescription, info.Description);
if (info.EnableAutoDownload) {
Console.WriteLine(App.UpdateDownloading);
var fullPath = Path.GetFullPath($"update.{Path.GetExtension(info.PackageLink)}");
File.WriteAllBytes(fullPath, GetBucketFileAsByteArray(info.PackageLink));
Console.WriteLine(App.UpdateDownloadFinish);
ShellOpen(fullPath);
var tmpPath = Path.GetTempFileName();
File.WriteAllBytes(tmpPath, GetBucketFileAsByteArray(info.PackageLink));
var updaterArgs = $"{Environment.ProcessId}|{Environment.ProcessPath}|{tmpPath}";
var updaterPath = Path.Combine(GlobalVars.DataPath, "update.exe");
var updaterHash = App.Updater.MD5Hash();
if (!File.Exists(updaterPath) || File.ReadAllBytes(updaterPath).MD5Hash() != updaterHash) {
File.WriteAllBytes(updaterPath, App.Updater);
}
ShellOpen(updaterPath, updaterArgs.ToBytes().ToBase64());
GlobalVars.PauseOnExit = false;
Environment.Exit(0);
}
Console.WriteLine(App.DownloadLink, info.PackageLink);
@@ -102,13 +105,13 @@ public static class Utils {
}
}
if (useLocalLib) {
Console.WriteLine(@"Use local native lib.");
File.Copy(Path.Combine(GlobalVars.AppPath, "YaeAchievementLib.dll"), GlobalVars.LibPath, true);
Console.WriteLine(@"[DEBUG] Use local native lib.");
File.Copy(Path.Combine(GlobalVars.AppPath, "YaeAchievementLib.dll"), GlobalVars.LibFilePath, true);
} else if (info.EnableLibDownload) {
File.WriteAllBytes(GlobalVars.LibPath, GetBucketFileAsByteArray("schicksal/lib.dll"));
File.WriteAllBytes(GlobalVars.LibFilePath, GetBucketFileAsByteArray("schicksal/lib.dll"));
}
}
public static void CheckSelfIsRunning() {
Process.EnterDebugMode();
var cur = Process.GetCurrentProcess();
@@ -122,13 +125,17 @@ public static class Utils {
}
// ReSharper disable once UnusedMethodReturnValue.Global
public static bool ShellOpen(string path) {
public static bool ShellOpen(string path, string? args = null) {
try {
var startInfo = new ProcessStartInfo {
FileName = path,
UseShellExecute = true
};
if (args != null) {
startInfo.Arguments = args;
}
return new Process {
StartInfo = {
FileName = path,
UseShellExecute = true
}
StartInfo = startInfo
}.Start();
} catch (Exception) {
return false;
@@ -161,8 +168,10 @@ public static class Utils {
public static void InstallExitHook() {
AppDomain.CurrentDomain.ProcessExit += (_, _) => {
proc?.Kill();
Console.WriteLine(App.PressKeyToExit);
Console.ReadKey();
if (GlobalVars.PauseOnExit) {
Console.WriteLine(App.PressKeyToExit);
Console.ReadKey();
}
};
}
@@ -189,18 +198,32 @@ public static class Utils {
Environment.Exit(-1);
};
}
private static bool CheckGenshinIsLatestVersion(string path) {
#if DEBUG
return true;
#else
return File.Exists(path) && File.ReadAllBytes(path).MD5Hash()
is "34433aa962523e55213c596d4e6b1f9c"
or "1fa8e1445b8121d5d1b5c1e6a8daa905"; // TODO: Use api
#endif
}
// ReSharper disable once UnusedMethodReturnValue.Global
public static Thread StartAndWaitResult(string exePath, Func<string, bool> onReceive) {
if (!CheckGenshinIsLatestVersion(exePath)) {
Console.WriteLine(App.GenshinHashError);
Environment.Exit(0);
}
AppDomain.CurrentDomain.ProcessExit += (_, _) => {
try {
File.Delete(GlobalVars.LibPath);
File.Delete(GlobalVars.LibFilePath);
} catch (Exception) { /* ignored */ }
};
if (!Injector.CreateProcess(exePath, out var hProcess, out var hThread, out var pid)) {
Environment.Exit(new Win32Exception().PrintMsgAndReturnErrCode("ICreateProcess fail"));
}
if (Injector.LoadLibraryAndInject(hProcess, GlobalVars.LibPath) != 0) {
if (Injector.LoadLibraryAndInject(hProcess, GlobalVars.LibFilePath) != 0) {
if (!Native.TerminateProcess(hProcess, 0)) {
Environment.Exit(new Win32Exception().PrintMsgAndReturnErrCode("TerminateProcess fail"));
}
@@ -251,22 +274,30 @@ public static class Utils {
using var root = Registry.LocalMachine;
using var sub = root.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall")!;
var installed = sub.GetSubKeyNames()
.Select(subKeyName => sub.OpenSubKey(subKeyName))
.Select(subKeyName => {
try {
return sub.OpenSubKey(subKeyName);
} catch (Exception) {
return null;
}
})
.Select(item => item?.GetValue("DisplayName") as string ?? string.Empty)
.Any(name => name.Contains("Microsoft Visual C++ 2022 X64 "));
if (!installed) {
Console.WriteLine(App.VcRuntimeDownload);
var pkgPath = Path.Combine(GlobalVars.AppPath, "vc_redist.x64.exe");
await using var stream = await CHttpClient.Value.GetStreamAsync("https://aka.ms/vs/17/release/vc_redist.x64.exe");
await using var output = File.OpenWrite(pkgPath);
await stream.CopyToAsync(output);
var pkgPath = Path.Combine(GlobalVars.DataPath, "vc_redist.x64.exe");
var bytes = await CHttpClient.GetByteArrayAsync("https://aka.ms/vs/17/release/vc_redist.x64.exe");
await File.WriteAllBytesAsync(pkgPath, bytes);
Console.WriteLine(App.VcRuntimeInstalling);
_ = new Process {
using var process = new Process {
StartInfo = {
FileName = pkgPath,
Arguments = "/install /passive /norestart"
}
}.Start();
};
process.Start();
await process.WaitForExitAsync();
File.Delete(pkgPath);
}
}
}

View File

@@ -60,7 +60,7 @@ public static class Native {
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool CloseHandle(IntPtr hObject);
[DllImport("kernel32.dll")]
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr CreateRemoteThread(
IntPtr hProcess,
IntPtr lpThreadAttributes,
@@ -101,19 +101,19 @@ public static class Native {
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr SetClipboardData(uint uFormat, IntPtr data);
[DllImport("user32.dll")]
[DllImport("user32.dll", SetLastError = true)]
public static extern bool EmptyClipboard();
[DllImport("gdi32.dll")]
[DllImport("gdi32.dll", SetLastError = true)]
public static extern int GetDeviceCaps(IntPtr hdc, int nIndex);
[DllImport("user32.dll")]
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr GetDC(IntPtr hWnd);
[DllImport("user32.dll")]
[DllImport("user32.dll", SetLastError = true)]
public static extern bool ReleaseDC(IntPtr hWnd, IntPtr hdc);
[DllImport("kernel32.dll")]
[DllImport("kernel32.dll", SetLastError = true)]
public static extern uint WaitForSingleObject(IntPtr handle, ulong dwMilliseconds);
}