Skip to content

Instantly share code, notes, and snippets.

@esterTion
Last active April 26, 2020 18:09
Show Gist options
  • Save esterTion/058e3762948b3eaa89fc2882e785b9e6 to your computer and use it in GitHub Desktop.
Save esterTion/058e3762948b3eaa89fc2882e785b9e6 to your computer and use it in GitHub Desktop.
Decreasing Arcaea score!
Build with theos
{ Filter = { Executables = ( "Arc-mobile" ); }; }
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
<?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>
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"
#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