Last active
April 26, 2020 18:09
-
-
Save esterTion/058e3762948b3eaa89fc2882e785b9e6 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Decreasing Arcaea score! | |
Build with theos |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ Filter = { Executables = ( "Arc-mobile" ); }; } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Package: com.estertion.arc-countdown-score | |
Name: Arcaea Countdown Score | |
Depends: mobilesubstrate | |
Version: 1.5 | |
Architecture: iphoneos-arm | |
Description: Decreasing Arcaea score! | |
Maintainer: esterTion | |
Author: esterTion | |
Section: Tweaks |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="UTF-8"?> | |
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | |
<plist version="1.0"> | |
<dict> | |
<key>entry</key> | |
<dict> | |
<key>cell</key> | |
<string>PSLinkCell</string> | |
<key>icon</key> | |
<string>Arcaea.png</string> | |
<key>label</key> | |
<string>ArcaeaCountdownScore</string> | |
</dict> | |
<key>items</key> | |
<array> | |
<dict> | |
<key>cell</key> | |
<string>PSGroupCell</string> | |
<key>isStaticText</key> | |
<true/> | |
<key>label</key> | |
<string>ArcaeaCountdownScore</string> | |
</dict> | |
<dict> | |
<key>cell</key> | |
<string>PSSwitchCell</string> | |
<key>default</key> | |
<true/> | |
<key>defaults</key> | |
<string>com.estertion.arc-countdown-score</string> | |
<key>key</key> | |
<string>enabled</string> | |
<key>label</key> | |
<string>启用</string> | |
</dict> | |
<dict> | |
<key>cell</key> | |
<string>PSSwitchCell</string> | |
<key>default</key> | |
<false/> | |
<key>defaults</key> | |
<string>com.estertion.arc-countdown-score</string> | |
<key>key</key> | |
<string>spure_add</string> | |
<key>label</key> | |
<string>大pure做加法</string> | |
</dict> | |
</array> | |
<key>title</key> | |
<string>LocalIAPStore</string> | |
</dict> | |
</plist> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
include $(THEOS)/makefiles/common.mk | |
TWEAK_NAME = ArcaeaCountdownScore | |
ArcaeaCountdownScore_FILES = Tweak.xm | |
ArcaeaCountdownScore_CFLAGS = -fobjc-arc | |
include $(THEOS_MAKE_PATH)/tweak.mk | |
after-install:: | |
install.exec "killall -9 Arc-mobile" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import <substrate.h> | |
#import <dlfcn.h> | |
#import <mach-o/dyld.h> | |
typedef struct ScoreState { | |
pointer_t a1; | |
char a2[4]; | |
int noteCount; | |
int maxCombo; | |
int score; | |
int score_chk; // score / 3 | |
float hp; | |
int combo; | |
int shiny_pure; | |
int pure; | |
int far; | |
int lost; | |
char gap[11 * 4]; | |
int skill_type; | |
} ScoreState; | |
static long nextScoreStateObjPtr = 0; | |
static bool spure_add = false; | |
static bool non_pm_sudden_death = false; | |
int (*orig_ArcUtil_calculateScore)(int lost, int far, int pure, int shiny_pure, int note_count); | |
int hacked_ArcUtil_calculateScore(int lost, int far, int pure, int shiny_pure, int note_count) { | |
if (nextScoreStateObjPtr) { | |
ScoreState *scoreState = (ScoreState*)nextScoreStateObjPtr; | |
#ifdef DEBUG | |
NSLog(@"[arc-score] ScoreState ptr:%lx nc:%d sp:%d p:%d f:%d l:%d", nextScoreStateObjPtr, scoreState->noteCount, scoreState->shiny_pure, scoreState->pure, scoreState->far, scoreState->lost); | |
#endif | |
note_count = scoreState->noteCount; | |
shiny_pure = scoreState->shiny_pure; | |
pure = scoreState->pure; | |
far = scoreState->far; | |
lost = scoreState->lost; | |
nextScoreStateObjPtr = 0; | |
int base = 10000000LL + note_count // 理论值 | |
- (pure - shiny_pure) - far - lost; // 已经没有的大p | |
if (spure_add) { | |
base = 10000000LL + shiny_pure; | |
} | |
if (pure+far+lost < note_count) | |
return base - (1000000000LL * (5 * far + 10 * lost) / note_count + 999) / 1000; // 已经产生的lost和far | |
} | |
#ifdef DEBUG | |
NSLog(@"[arc-score ArcUtil_calculateScore] lost:%d far:%d pure:%d shiny_pure:%d note_count:%d", lost, far, pure, shiny_pure, note_count); | |
#endif | |
return orig_ArcUtil_calculateScore(lost, far, pure, shiny_pure, note_count); | |
} | |
long (*orig_ScoreState_init)(ScoreState* a1, long a2, int a3, long a4); | |
long hacked_ScoreState_init(ScoreState* a1, long a2, int a3, long a4) { | |
long val = orig_ScoreState_init(a1, a2, a3, a4); | |
a1->score = 10000000LL + a1->noteCount; | |
a1->score_chk = a1->score / 3; | |
return val; | |
} | |
long (*orig_ScoreState_hitNote)(long a1, long a2, int a3, int a4, long a5); | |
long hacked_ScoreState_hitNote(long a1, long a2, int a3, int a4, long a5) { | |
ScoreState *scoreState = (ScoreState*)a1; | |
if (non_pm_sudden_death && a3 > 1 && scoreState->skill_type == 2) { | |
scoreState->hp = 0; | |
nextScoreStateObjPtr = 0; | |
return 0; | |
} | |
long returnVal = orig_ScoreState_hitNote(a1, a2, a3, a4, a5); | |
nextScoreStateObjPtr = a1; | |
int score = hacked_ArcUtil_calculateScore(scoreState->lost, scoreState->far, scoreState->pure, scoreState->shiny_pure, scoreState->noteCount); | |
scoreState->score = score; | |
scoreState->score_chk = score / 3; | |
return returnVal; | |
} | |
int (*orig_ScoreState_missNote)(long a1, long a2); | |
int hacked_ScoreState_missNote(long a1, long a2) { | |
ScoreState *scoreState = (ScoreState*)a1; | |
if (non_pm_sudden_death && scoreState->skill_type == 2) { | |
scoreState->hp = 0; | |
} | |
int returnVal = orig_ScoreState_missNote(a1, a2); | |
nextScoreStateObjPtr = a1; | |
if (scoreState->skill_type == 2 && scoreState->hp == 0) nextScoreStateObjPtr = 0; | |
int score = hacked_ArcUtil_calculateScore(scoreState->lost, scoreState->far, scoreState->pure, scoreState->shiny_pure, scoreState->noteCount); | |
scoreState->score = score; | |
scoreState->score_chk = score / 3; | |
#ifdef DEBUG | |
NSLog(@"[arc-score ScoreState:missNote] score:%d", score); | |
#endif | |
return returnVal; | |
} | |
NSMutableDictionary *setting = NULL; | |
NSString* ACSGetSettingValue(NSString *key, NSString *defaultValue) { | |
if (setting == NULL) return defaultValue; | |
NSObject *value = [setting objectForKey:key]; | |
if (value == NULL) return defaultValue; | |
NSString *valueStr; | |
if ([value isKindOfClass:[NSString class]]) { | |
valueStr = (NSString *)value; | |
} else if ([value isKindOfClass:[NSNumber class]]) { | |
valueStr = [(NSNumber *)value stringValue]; | |
} else { | |
valueStr = defaultValue; | |
} | |
return valueStr; | |
} | |
void showFoundFunctionOffsetAlert() { | |
dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC); | |
dispatch_after(delay, dispatch_get_main_queue(), ^(void) { | |
__block UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Arcaea Countdown Score" | |
message:@"Function hooked!" | |
preferredStyle:UIAlertControllerStyleAlert]; | |
UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:[[NSBundle bundleWithIdentifier:@"com.apple.UIKit"] localizedStringForKey:@"Dismiss" value:@"" table:nil] | |
style:UIAlertActionStyleDefault | |
handler:^(UIAlertAction * action) {}]; | |
[alert addAction:defaultAction]; | |
[[UIApplication sharedApplication].keyWindow.rootViewController presentViewController:alert animated:YES completion:nil]; | |
dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC); | |
dispatch_after(delay, dispatch_get_main_queue(), ^(void) { | |
if (alert) { | |
[alert dismissViewControllerAnimated:YES completion:NULL]; | |
} | |
}); | |
}); | |
} | |
bool instcmp(uint8_t* ptr1, uint8_t* ptr2, unsigned int len) { | |
for (int i=0; i<len; i++) { | |
if (ptr1[i] != ptr2[i]) return false; | |
} | |
return true; | |
} | |
%ctor { | |
setting = [[NSMutableDictionary alloc] initWithContentsOfFile: @"/var/mobile/Library/Preferences/com.estertion.arc-countdown-score.plist"]; | |
NSString *enabled = ACSGetSettingValue(@"enabled", @"1"); | |
if ([enabled isEqualToString:@"0"]) return; | |
NSString *spure_add_str = ACSGetSettingValue(@"spure_add", @"0"); | |
spure_add = [spure_add_str isEqualToString:@"1"]; | |
NSString *non_pm_sudden_death_str = ACSGetSettingValue(@"non_pm_sudden_death", @"0"); | |
non_pm_sudden_death = [non_pm_sudden_death_str isEqualToString:@"1"]; | |
unsigned long ScoreState_init = (unsigned long) MSFindSymbol(NULL, "__ZN10ScoreState4initEP10LogicChart12PlayModifierP16CharacterAbility"); | |
if (ScoreState_init) { | |
NSLog(@"[arc-score] found sytmbol for ScoreState::init at %lx", ScoreState_init); | |
} | |
#ifndef __arm__ | |
bool found_calculateScore = false; | |
bool found_hitNote = false; | |
bool found_missNote = false; | |
int *ptr = (int*)(_dyld_get_image_vmaddr_slide(0) + 0x100000000); | |
int *ptr_top = (int*)((char*)ptr + 5000000); | |
unsigned long ArcUtil_calculateScore, ScoreState_hitNote, ScoreState_missNote; | |
ArcUtil_calculateScore = (unsigned long)MSFindSymbol(NULL, "__ZN7ArcUtil14calculateScoreEiiiii"); | |
if (ArcUtil_calculateScore) { | |
found_calculateScore = true; | |
NSLog(@"[arc-score] found sytmbol for calculateScore at %lx", ArcUtil_calculateScore); | |
} | |
ScoreState_hitNote = (unsigned long)MSFindSymbol(NULL, "__ZN10ScoreState7hitNoteEP9LogicNote15HitAccuracyType13LateEarlyTypei"); | |
if (ScoreState_hitNote) { | |
found_hitNote = true; | |
NSLog(@"[arc-score] found sytmbol for hitNote at %lx", ScoreState_hitNote); | |
} | |
ScoreState_missNote = (unsigned long)MSFindSymbol(NULL, "__ZN10ScoreState8missNoteEP9LogicNotei"); | |
if (ScoreState_missNote) { | |
found_missNote = true; | |
NSLog(@"[arc-score] found sytmbol for missNote at %lx", ScoreState_missNote); | |
} | |
NSLog(@"[arc-score] start program search"); | |
uint8_t calculateScore_inst[] = { | |
0x5f, 0x00, 0x04, 0x6b, | |
0x81, 0x00, 0x00, 0x54, | |
0x08, 0xd0, 0x92, 0x52, | |
0x08, 0x13, 0xa0, 0x72 | |
}; | |
while (ptr < ptr_top) { | |
if (!found_calculateScore) { | |
if (instcmp((uint8_t*)ptr, calculateScore_inst, 16)) { | |
ArcUtil_calculateScore = (unsigned long)ptr; | |
found_calculateScore = true; | |
NSLog(@"[arc-score] found calculateScore at %lx", ArcUtil_calculateScore); | |
} | |
} | |
if (!found_hitNote) { | |
if (*ptr == 0x6dbb23e9 && *(ptr+1) == 0xa9015ff8 && *(ptr+2) == 0xa90257f6 && *(ptr+6) == 0xaa0403f4) { | |
ScoreState_hitNote = (unsigned long)ptr; | |
found_hitNote = true; | |
NSLog(@"[arc-score] found hitNote at %lx", ScoreState_hitNote); | |
} | |
} | |
if (!found_missNote) { | |
if ((*ptr & 0xff00ffff) == 0xa9004ff4 && (*(ptr+1) & 0xff00ffff) == 0xa9007bfd && *(ptr+5) == 0xf9400028 && *(ptr+6) == 0xf9401d08 && *(ptr+7) == 0x320003e1) { | |
ScoreState_missNote = (unsigned long)(ptr - ((*ptr & 0xff0000) >> 16)); | |
found_missNote = true; | |
NSLog(@"[arc-score] found missNote at %lx", ScoreState_missNote); | |
} | |
} | |
if (found_calculateScore && found_hitNote && found_missNote) break; | |
ptr++; | |
} | |
NSLog(@"[arc-score] end program search"); | |
if (found_calculateScore && found_hitNote && found_missNote) { | |
NSLog(@"[arc-score] hooked"); | |
MSHookFunction((void *)ArcUtil_calculateScore, (void *)hacked_ArcUtil_calculateScore, (void **)&orig_ArcUtil_calculateScore); | |
MSHookFunction((void *)ScoreState_hitNote, (void *)hacked_ScoreState_hitNote, (void **)&orig_ScoreState_hitNote); | |
MSHookFunction((void *)ScoreState_missNote, (void *)hacked_ScoreState_missNote, (void **)&orig_ScoreState_missNote); | |
if (ScoreState_init) MSHookFunction((void *)ScoreState_init, (void *)hacked_ScoreState_init, (void **)&orig_ScoreState_init); | |
showFoundFunctionOffsetAlert(); | |
} | |
#else | |
bool found_calculateScore = false; | |
bool found_hitNote = false; | |
bool found_missNote = false; | |
uint16_t *ptr = (uint16_t*)(_dyld_get_image_vmaddr_slide(0) + 0x100000); | |
uint16_t *ptr_top = (uint16_t*)((char*)ptr + 5000000); | |
unsigned long ArcUtil_calculateScore, ScoreState_hitNote, ScoreState_missNote; | |
ArcUtil_calculateScore = (unsigned long)MSFindSymbol(NULL, "__ZN7ArcUtil14calculateScoreEiiiii"); | |
if (ArcUtil_calculateScore) { | |
found_calculateScore = true; | |
NSLog(@"[arc-score] found sytmbol for calculateScore at %lx", ArcUtil_calculateScore); | |
} | |
ScoreState_hitNote = (unsigned long)MSFindSymbol(NULL, "__ZN10ScoreState7hitNoteEP9LogicNote15HitAccuracyType13LateEarlyTypei"); | |
if (ScoreState_hitNote) { | |
found_hitNote = true; | |
NSLog(@"[arc-score] found sytmbol for hitNote at %lx", ScoreState_hitNote); | |
} | |
ScoreState_missNote = (unsigned long)MSFindSymbol(NULL, "__ZN10ScoreState8missNoteEP9LogicNotei"); | |
if (ScoreState_missNote) { | |
found_missNote = true; | |
NSLog(@"[arc-score] found sytmbol for missNote at %lx", ScoreState_missNote); | |
} | |
NSLog(@"[arc-score] start program search"); | |
uint8_t calculateScore_inst[] = { | |
0xb0, 0xb5, 0x02, 0xaf, | |
0x10, 0x46, 0xba, 0x68, | |
0x49, 0xf2, 0x80, 0x65, | |
0x1c, 0x46, 0xc0, 0xf2 | |
}, hitNote_inst[] = { | |
0xf0, 0xb5, 0x03, 0xaf, | |
0x2d, 0xe9, 0x00, 0x05, | |
0x2d, 0xed, 0x02, 0x8b, | |
0x81, 0xb0, 0x04, 0x46 | |
}, missNote_inst[] = { | |
0x04, 0x46, 0x08, 0x68, | |
0x0d, 0x46, 0xc3, 0x69, | |
0x08, 0x46, 0x01, 0x21 | |
}; | |
while (ptr < ptr_top) { | |
// b0b502af 1046ba68 49f28065 1c46c0f2 | |
if (!found_calculateScore) { | |
if (instcmp((uint8_t*)ptr, calculateScore_inst, 16)) { | |
ArcUtil_calculateScore = (unsigned long)ptr |1; | |
found_calculateScore = true; | |
NSLog(@"[arc-score] found calculateScore at %lx", ArcUtil_calculateScore - _dyld_get_image_vmaddr_slide(0)); | |
} | |
} | |
// f0b503af 2de90005 2ded028b 81b00446 | |
if (!found_hitNote) { | |
if (instcmp((uint8_t*)ptr, hitNote_inst, 16)) { | |
ScoreState_hitNote = (unsigned long)ptr |1; | |
found_hitNote = true; | |
NSLog(@"[arc-score] found hitNote at %lx", ScoreState_hitNote - _dyld_get_image_vmaddr_slide(0)); | |
} | |
} | |
// 04460868 0d46c369 08460121 | |
if (!found_missNote) { | |
if (instcmp((uint8_t*)ptr, missNote_inst, 12)) { | |
while (*(ptr-1) != 0x3fe9) ptr--; | |
ScoreState_missNote = (unsigned long)ptr |1; | |
found_missNote = true; | |
NSLog(@"[arc-score] found missNote at %lx", ScoreState_missNote - _dyld_get_image_vmaddr_slide(0)); | |
} | |
} | |
if (found_calculateScore && found_hitNote && found_missNote) break; | |
ptr++; | |
} | |
NSLog(@"[arc-score] end program search"); | |
if (found_calculateScore && found_hitNote && found_missNote) { | |
NSLog(@"[arc-score] hooked"); | |
MSHookFunction((void *)ArcUtil_calculateScore, (void *)hacked_ArcUtil_calculateScore, (void **)&orig_ArcUtil_calculateScore); | |
MSHookFunction((void *)ScoreState_hitNote, (void *)hacked_ScoreState_hitNote, (void **)&orig_ScoreState_hitNote); | |
MSHookFunction((void *)ScoreState_missNote, (void *)hacked_ScoreState_missNote, (void **)&orig_ScoreState_missNote); | |
if (ScoreState_init) MSHookFunction((void *)ScoreState_init, (void *)hacked_ScoreState_init, (void **)&orig_ScoreState_init); | |
showFoundFunctionOffsetAlert(); | |
} | |
#endif | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment