ViewController.m 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  1. //
  2. // ViewController.m
  3. // meridianTV
  4. //
  5. // Created by Kevin Bradley on 6/24/18.
  6. // Copyright © 2018 Ben Sparkes. All rights reserved.
  7. //
  8. #import "ViewController.h"
  9. #import "helpers.h"
  10. #import "jailbreak.h"
  11. #import <sys/utsname.h>
  12. #import <Foundation/Foundation.h>
  13. #import "PureLayout.h"
  14. #import "UIColor+Additions.h"
  15. @interface ViewController ()
  16. @property (strong, nonatomic) FocusedButton *goButton;
  17. @property (strong, nonatomic) UIButton *creditsButton;
  18. @property (strong, nonatomic) UIButton *websiteButton;
  19. @property (strong, nonatomic) UIActivityIndicatorView *progressSpinner;
  20. @property (strong, nonatomic) UITextView *textArea;
  21. @property (strong, nonatomic) UILabel *versionLabel;
  22. @end
  23. NSString *Version = @"Meridian: Internal Beta 7";
  24. NSOperatingSystemVersion osVersion;
  25. id thisClass;
  26. bool has_run_once = false;
  27. bool jailbreak_has_run = false;
  28. @implementation FocusedButton
  29. - (instancetype)initWithCoder:(NSCoder *)coder
  30. {
  31. self = [super initWithCoder:coder];
  32. if (self) {
  33. self.layer.cornerRadius = 5;
  34. self.backgroundColor = [UIColor lightGrayColor];
  35. self.focusColor = [UIColor redColor];
  36. self.unfocusedColor = [UIColor lightGrayColor];
  37. }
  38. return self;
  39. }
  40. - (void)buttonColors:(UIColor *)focusedColor andUnfocused:(UIColor *)unfocusedColor {
  41. self.focusColor = focusedColor;
  42. self.unfocusedColor = unfocusedColor;
  43. self.backgroundColor = unfocusedColor;
  44. }
  45. - (void)didUpdateFocusInContext:(UIFocusUpdateContext *)context withAnimationCoordinator:(UIFocusAnimationCoordinator *)coordinator {
  46. [coordinator addCoordinatedAnimations:^{
  47. if (self.focused) {
  48. self.backgroundColor = self.focusColor;
  49. self.transform = CGAffineTransformMakeScale(1.1, 1.1);
  50. self.layer.shadowColor = [UIColor blackColor].CGColor;
  51. self.layer.shadowOffset = CGSizeMake(0, 27);
  52. self.layer.shadowOpacity = 0.25;
  53. self.layer.shadowRadius = 10;
  54. self.clipsToBounds = NO;
  55. }
  56. else {
  57. self.transform = CGAffineTransformIdentity;
  58. self.backgroundColor = self.unfocusedColor;
  59. self.clipsToBounds = YES;
  60. }
  61. } completion:nil];
  62. }
  63. @end
  64. @implementation ViewController
  65. - (void)customTVSetup {
  66. UIImageView *bgImageView = [[UIImageView alloc] initForAutoLayout];
  67. [self.view addSubview:bgImageView];
  68. [bgImageView autoPinEdgesToSuperviewEdges];
  69. [bgImageView setImage:[UIImage imageNamed:@"DarkMap.png"]];
  70. UILabel *meridianTV = [[UILabel alloc] initForAutoLayout];
  71. [self.view addSubview:meridianTV];
  72. [meridianTV autoAlignAxisToSuperviewAxis:ALAxisVertical];
  73. [meridianTV autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:160];
  74. [meridianTV setFont:[UIFont systemFontOfSize:205 weight:UIFontWeightHeavy]];
  75. [meridianTV setText:@"meridianTV"];
  76. [meridianTV setTextColor:[UIColor whiteColor]];
  77. self.goButton = [[FocusedButton alloc] initForAutoLayout] ;
  78. [self.goButton autoSetDimensionsToSize:CGSizeMake(250, 100)];
  79. [self.goButton setTitle:@"jailbreak" forState:UIControlStateFocused];
  80. [self.goButton buttonColors:[UIColor colorFromHex:@"DB1E00"]
  81. andUnfocused:[UIColor darkTextColor]];
  82. [self.view addSubview:self.goButton];
  83. [self.goButton autoCenterInSuperview];
  84. [self.goButton addTarget:self action:@selector(goButtonPressed:) forControlEvents:UIControlEventPrimaryActionTriggered];
  85. self.versionLabel = [[UILabel alloc] initForAutoLayout];
  86. self.versionLabel.textColor = [UIColor whiteColor];
  87. [self.view addSubview:self.versionLabel];
  88. [self.versionLabel autoAlignAxisToSuperviewAxis:ALAxisVertical];
  89. [self.versionLabel autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:self.goButton withOffset:5];
  90. self.textArea = [[UITextView alloc] initForAutoLayout];
  91. [self.view addSubview:self.textArea];
  92. [self.textArea autoAlignAxisToSuperviewAxis:ALAxisVertical];
  93. [self.textArea autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:self.versionLabel];
  94. [self.textArea autoMatchDimension:ALDimensionWidth toDimension:ALDimensionWidth ofView:self.view withMultiplier:0.8];
  95. [self.textArea autoPinEdgeToSuperviewEdge:ALEdgeBottom withInset:40];
  96. //[self.goButton setBackgroundColor:[UIColor colorFromHex:@"DB1E00"]];
  97. [self.goButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
  98. [self.textArea setBackgroundColor:[UIColor blackColor]];
  99. [self.textArea setTextColor:[UIColor colorFromHex:@"CACBCA"]];
  100. //DB1E00
  101. //CACBCA
  102. }
  103. - (void)viewDidLoad {
  104. [super viewDidLoad];
  105. thisClass = self;
  106. [self customTVSetup];
  107. [self.goButton.layer setCornerRadius:5];
  108. [self.creditsButton.layer setCornerRadius:5];
  109. [self.websiteButton.layer setCornerRadius:5];
  110. NSString *buildDate = [NSString stringWithContentsOfFile:[NSString stringWithFormat:@"%s", bundled_file("build_time")]
  111. encoding:NSUTF8StringEncoding
  112. error:nil];
  113. [self.versionLabel setText:[NSString stringWithFormat:@"%@: %@", Version, buildDate]];
  114. jailbreak_has_run = check_for_jailbreak();
  115. //[self doUpdateCheck];
  116. // Log current device and version info
  117. osVersion = [[NSProcessInfo processInfo] operatingSystemVersion];
  118. [self writeTextPlain:[NSString stringWithFormat:@"> %@", Version]];
  119. if (osVersion.majorVersion != 10) {
  120. [self writeTextPlain:@"> Meridian does not work on versions of iOS other than iOS 10."];
  121. [self writeTextPlain:[NSString stringWithFormat:@"> found iOS version %@", [self getVersionString]]];
  122. [self.goButton setHidden:YES];
  123. return;
  124. }
  125. [self writeTextPlain:[NSString stringWithFormat:@"> %s on iOS %@ (Build %@)",
  126. [self getDeviceIdentifier],
  127. [self getVersionString],
  128. [self getBuildString]]];
  129. if (jailbreak_has_run) {
  130. [self writeTextPlain:@"> already jailbroken."];
  131. // set done button
  132. [self.goButton setTitle:@"done" forState:UIControlStateFocused];
  133. // aaaaand grey it out
  134. [self.goButton setEnabled:NO];
  135. [self.goButton setAlpha:0.5];
  136. return;
  137. }
  138. /*
  139. // Device is already jailbroken, but not with Meridian
  140. if (file_exists("/private/var/lib/dpkg/status") == 0 &&
  141. file_exists("/meridian/.installed") != 0) {
  142. [self writeTextPlain:@"this device has already been jailbroken with another tool. please run Cydia Eraser to wipe this device to ensure you encounter no issues with Meridian"];
  143. [self.goButton setTitle:@"please erase" forState:UIControlStateFocused];
  144. [self.goButton setEnabled:NO];
  145. [self.goButton setAlpha:0.5];
  146. return;
  147. }
  148. */
  149. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^(void) {
  150. int waitTime;
  151. while ((waitTime = 90 - uptime()) > 0) {
  152. dispatch_async(dispatch_get_main_queue(), ^{
  153. [self.goButton setTitle:[NSString stringWithFormat:@"wait: %d", waitTime] forState:UIControlStateFocused];
  154. [self.goButton setTitle:[NSString stringWithFormat:@"wait: %d", waitTime] forState:UIControlStateNormal];
  155. [self.goButton setTitle:[NSString stringWithFormat:@"wait: %d", waitTime] forState:UIControlStateDisabled];
  156. [self.goButton setEnabled:false];
  157. [self.goButton setAlpha:0.6];
  158. });
  159. sleep(1);
  160. }
  161. dispatch_async(dispatch_get_main_queue(), ^{
  162. [self.goButton setTitle:@"go" forState:UIControlStateFocused];
  163. [self.goButton setEnabled:true];
  164. [self.goButton setAlpha:1];
  165. [self writeTextPlain:@"> ready."];
  166. });
  167. });
  168. NSLog(@"App bundle directory: %s", bundle_path());
  169. }
  170. - (IBAction)goButtonPressed:(UIButton *)sender {
  171. // when jailbreak runs, 'go' button is
  172. // turned to 'respring'
  173. if (jailbreak_has_run) {
  174. int rv = respring();
  175. if (rv != 0) {
  176. [self writeTextPlain:@"failed to respring."];
  177. }
  178. return;
  179. }
  180. // if we've run once, just reboot
  181. if (has_run_once) {
  182. [self.goButton setHidden:YES];
  183. restart_device();
  184. return;
  185. }
  186. // set up the UI to 'running' state
  187. [self.goButton setEnabled:NO];
  188. [self.goButton setHidden:YES];
  189. [self.creditsButton setEnabled:NO];
  190. self.creditsButton.alpha = 0.5;
  191. [self.websiteButton setEnabled:NO];
  192. self.websiteButton.alpha = 0.5;
  193. [self.progressSpinner startAnimating];
  194. has_run_once = true;
  195. // background thread so we can update the UI
  196. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^(void) {
  197. int ret = makeShitHappen(self);
  198. if (ret != 0) {
  199. NSLog(@"MERIDIAN HAS FAILED TO RUN :(");
  200. dispatch_async(dispatch_get_main_queue(), ^{
  201. [self exploitFailed];
  202. });
  203. return;
  204. }
  205. dispatch_async(dispatch_get_main_queue(), ^{
  206. [self exploitSucceeded];
  207. });
  208. });
  209. }
  210. - (IBAction)websiteButtonPressed:(UIButton *)sender {
  211. [[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"https://meridian.sparkes.zone"]
  212. options:@{}
  213. completionHandler:nil];
  214. }
  215. - (char *)getDeviceIdentifier {
  216. static struct utsname u;
  217. uname(&u);
  218. return u.machine;
  219. }
  220. - (NSString *)getVersionString {
  221. return [NSString stringWithFormat:@"%ld.%ld.%ld",
  222. (long)osVersion.majorVersion,
  223. (long)osVersion.minorVersion,
  224. (long)osVersion.patchVersion];
  225. }
  226. - (NSString *)getBuildString {
  227. NSString *verString = [[NSProcessInfo processInfo] operatingSystemVersionString];
  228. // wish there was a better way of doing this (hopefully there is)
  229. NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"14[A-Za-z0-9]{3,5}"
  230. options:0
  231. error:nil];
  232. NSRange range = [regex rangeOfFirstMatchInString:verString options:0 range:NSMakeRange(0, [verString length])];
  233. return [verString substringWithRange:range];
  234. }
  235. - (void)exploitSucceeded {
  236. jailbreak_has_run = true;
  237. [self writeTextPlain:@"\n> your device has been freed! \n"];
  238. [self writeTextPlain:@"note: please click 'respring' to get this party started :) \n"];
  239. execprog("/bin/ps", (const char **)&(const char *[]) {
  240. "/bin/ps",
  241. "awwwx",
  242. NULL
  243. });
  244. [self.progressSpinner stopAnimating];
  245. [self.goButton setEnabled:YES];
  246. [self.goButton setHidden:NO];
  247. [self.goButton setTitle:@"respring" forState:UIControlStateFocused];
  248. [self.creditsButton setEnabled:YES];
  249. self.creditsButton.alpha = 1;
  250. [self.websiteButton setEnabled:YES];
  251. self.websiteButton.alpha = 1;
  252. }
  253. - (void)exploitFailed {
  254. [self writeTextPlain:@"exploit failed. please reboot & try again."];
  255. [self.goButton setEnabled:YES];
  256. [self.goButton setHidden:NO];
  257. [self.goButton setTitle:@"reboot" forState:UIControlStateFocused];
  258. [self.creditsButton setEnabled:YES];
  259. [self.creditsButton setAlpha:1];
  260. [self.websiteButton setEnabled:YES];
  261. [self.websiteButton setAlpha:1];
  262. [self.progressSpinner stopAnimating];
  263. }
  264. - (void)doUpdateCheck {
  265. // skip the version check if we're running an internal build
  266. if ([Version containsString:@"Internal"]) {
  267. return;
  268. }
  269. NSURL *url = [NSURL URLWithString:@"https://meridian.sparkes.zone/latest"];
  270. NSURLSessionDataTask *downloadTask = [[NSURLSession sharedSession]
  271. dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *header, NSError *error) {
  272. if (error != nil) {
  273. NSLog(@"failed to get information from the update server.");
  274. return;
  275. }
  276. NSString *response = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
  277. if (response != Version) {
  278. [self doUpdatePopup:response];
  279. }
  280. }];
  281. [downloadTask resume];
  282. }
  283. - (void)doUpdatePopup:(NSString *)update {
  284. NSString *message = [NSString stringWithFormat:@"An update is available for Meridian: %@It can be downloaded from the website.", update];
  285. UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Meridian Update"
  286. message:message
  287. preferredStyle:UIAlertControllerStyleAlert];
  288. UIAlertAction *websiteAction = [UIAlertAction actionWithTitle:@"Website" style:UIAlertActionStyleDefault
  289. handler:^(UIAlertAction * action) {
  290. [[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"https://meridian.sparkes.zone"]
  291. options:@{}
  292. completionHandler:nil];
  293. }];
  294. UIAlertAction *closeAction = [UIAlertAction actionWithTitle:@"Close"
  295. style:UIAlertActionStyleCancel
  296. handler:nil];
  297. [alert addAction:websiteAction];
  298. [alert addAction:closeAction];
  299. [self presentViewController:alert animated:YES completion:nil];
  300. }
  301. - (void)writeText:(NSString *)message {
  302. dispatch_async(dispatch_get_main_queue(), ^{
  303. if (![message isEqual: @"done!"] && ![message isEqual:@"failed!"]) {
  304. NSLog(@"%@", message);
  305. _textArea.text = [_textArea.text stringByAppendingString:[NSString stringWithFormat:@"%@ ", message]];
  306. } else {
  307. _textArea.text = [_textArea.text stringByAppendingString:[NSString stringWithFormat:@"%@\n", message]];
  308. }
  309. NSRange bottom = NSMakeRange(_textArea.text.length - 1, 1);
  310. [self.textArea scrollRangeToVisible:bottom];
  311. });
  312. }
  313. - (void)writeTextPlain:(NSString *)message, ... {
  314. va_list args;
  315. va_start(args, message);
  316. message = [[NSString alloc] initWithFormat:[message stringByAppendingString:@"\n"] arguments:args];
  317. dispatch_async(dispatch_get_main_queue(), ^{
  318. _textArea.text = [_textArea.text stringByAppendingString:message];
  319. NSRange bottom = NSMakeRange(_textArea.text.length - 1, 1);
  320. [self.textArea scrollRangeToVisible:bottom];
  321. NSLog(@"%@", message);
  322. });
  323. va_end(args);
  324. }
  325. // kinda dumb, kinda lazy, ¯\_(ツ)_/¯
  326. void log_message(NSString *message) {
  327. [thisClass writeTextPlain:message];
  328. }
  329. @end