Jekyll2023-03-23T07:20:41+00:00https://geosn0w.github.io/feed.xmlGeoSn0wProgrammer. Hacking stuff. Failed ordinary man.Understanding iOS Tweaks and Battery Draining2019-03-15T00:00:00+00:002019-03-15T00:00:00+00:00https://geosn0w.github.io/Understanding-iOS-Tweaks-and-Battery-Draining<p>Recently I got in a heated discussion with a friend about tweaks and how a seemingly benign tweak that does nothing but to change a <code class="high">.plist</code> file can actually become a vector for serious battery draining. While discussing with the person about TetherMe, a tweak which unlocks the cellular data tethering, in the context of battery drain, I realized that some people only see one single dimension of a specific action which could potentially be a problem when you install tweaks. Let’s dive a bit into the idea of batter draining in the context of jailbreak tweaks.</p>
<h3 id="about-the-tetherme-discussion">About the TetherMe discussion</h3>
<p>I’ll start with TetherMe since it was the subject of a heated discussion between me and Pwn20wnd. See, there are some carriers that simply do not allow enabling the Tethering function. On a normal non-jailbroken device there’s no way to circumvent the carrier-imposed lock so you won’t be able to activate tethering which means power consumption of 0 due to tethering.</p>
<p>When jailbroken, you can install a tweak called <code class="high">TetherMe</code> (which is a great tweak by the way) that can circumvent the lock. The tweak itself does not drain any battery, but since you’ve installed it’s likely you want to use tethering and that will drain more power. How much power? Depends on how much you use the tethering, but the idea is that you now have the potential to draw more power which you didn’t have before installing the tweak. It’s just a matter of the perspective.</p>
<p align="center">
<img src="https://user-images.githubusercontent.com/15067741/54457638-33076300-4762-11e9-9c7b-76b7b9a86a03.png" />
</p>
<p>So the bottom line here? Yes, <code class="high">TetherMe</code> will draw close to no power, but what it allows you to do (circumvent carrier restrictions to activate and use unlimited tethering) has the potential to create more power draining. And yes, you will say “well that is fucking obvious, isn’t it?” Well, not for everyone. I was just asked if WiFi shouldn’t be drawing more power than Cellular Data (4G)… Some people really believe that they install the tweak to unlock the feature, enable the tethering thanks to it and the battery consumption will not be noticeable just because the tweak just unlocks an iOS feature.</p>
<h3 id="theming-and-graphically-intensive-tweaks">Theming and graphically intensive tweaks</h3>
<p>When jailbreaking your device, you may be like me and use the jailbreak for <code class="high">SSH</code>, file management and research, or you may be interested in the fun part of jailbreaking and install an awful lot of tweaks to customize every single part of iOS. While that can render the device of your dreams with everything looking exactly the way you’d love it to be, tweaks that add graphical elements tend to consume much more power. Take <code class="high">XenHTML</code> for example. It’s a nice tweak which allows a high degree of customization, but for that to be possible there’s extra memory used, extra CPU used, extra GPU used which would not be the case on stock iOS. Does it look good? Yes. Does it draw more power? Yes. The problem with XenHTML is not Xen itself but the Widgets people install. Some widgets are very aggresive to the battery while others result in close to no battery consumption. Tweaks that add Always-On displays, animations, extra graphical elements on the springboard and so on, tend to increase the battery consumption. Lockscreens, widgets, Imagine them like having extra apps running and eating the phone resources. The more tweaks the more consumption.</p>
<p>! WARNING! XenHTML itself (the bare tweak) does consume any significant power. It’s the widgets people install that can be very aggresive to the battery. Xen itself has a battery management feature built-in, however, it’s up to the widgets developers to ensure their XenHTML widgets don’t become battery hogs.</p>
<h3 id="other-sources-of-battery-drain">Other sources of battery drain</h3>
<p>Many people report tweaks like Activator and Smart Tap to create visible battery draining. That is normal. With such tweaks comes more computation. More things working in the background, more hooking. The more tweaks you have, the more battery consumption and this stays true especially for tweaks that are always active in the background or in the foreground. On older devices tweaks like IntelliScreenX and Winterboard can draw a lot of battery, and in general, tweaks that connect to the internet will add extra battery draining (and potentially even Data charges if you are not careful).</p>
<h3 id="drms-and-battery-draining">DRMs and battery draining</h3>
<p>That some tweaks nowadays use a sort of <code class="high">DRM (Digital Rights Management)</code> is not something new, however, depending on how the DRM is implemented it has the potential to do serious battery drain. See, if the DRM is constantly connecting to the internet to verify whatever license, it will consume more battery and potentially drive some Data charges too if you are not careful. Most DRMs I’ve seen on tweaks are a check that happens once, but it’s certainly possible to code your tweak to check constantly. This is a bad practice and only hurts the loyal customers of the tweak, but I won’t get into the ethics of using DRMs in this post.</p>
<h3 id="does-jailbreaking-itself-draws-more-power">Does jailbreaking itself draws more power?</h3>
<p>Even though some people believe it’s not the case, yes, jailbreaking draws some power. Nowadays jailbreaks use various daemons that run in the background to ensure that a specific iOS security feature is debilitated or as part of a jailbreak component (signing, etc.). Compared to stock iOS there’s more stuff running in the background and there will be more battery draining as well. Electra Jailbreak was noticeably known for being a serious battery hog. Whether due to the active components running in the background or because of the quality of the code, many people complained about it draining more battery.</p>
<p>Unfortunately, it’s not easy to estimate how much does the extra processing consume because it won’t appear in the battery settings, but on decent jailbreaks like Unc0ver it should not be a major battery drain. In fact, without any tweaks, Unc0ver itself draws a negligible amount of power. Keep in mind that just because it’s not major doesn’t mean the consumption is the same as stock iOS.</p>
<p>Now, the most battery drain will be from what you install using that jailbreak, not from the jailbreak components themselves (unless you use Electra), so usually, you should pay attention to what tweaks you install and do not install too many of them. Only what you find necessary. Anything that you don’t use but is enabled will draw a bit of power, use memory and CPU and result in some resources consumption you can simply avoid.</p>
<h3 id="is-it-a-good-idea-to-keep-the-phone-plugged-in-all-the-times">Is it a good idea to keep the phone plugged in all the times?</h3>
<p>In short, no. Lithium batteries do not like to stay at 100% all the time. It’s a state of high stress for the battery and it will eventually wear out losing its capacity to hold the charge. If you wanna store a phone you’re no longer using in a drawer, do not charge it to 100% and turn it off. It will hurt the battery in the long run. Charge it to about 55% and then turn it off. Same applies for completely discharging the battery before storing the phone. Don’t do that. Lithium batteries do not like the extreme states (Very low or very high power) for long periods of time.</p>
<p>Now, don’t expect that keeping it mostly plugged in while using it will damage the battery right away, but you will notice the battery health counter in the Battery Settings going down considerably after one year if you keep doing so. Now, Lithium batteries are consumables and they wear a tiny bit with every single full charging cycle they receive. <a href="https://www.apple.com/batteries/why-lithium-ion/">Original iPhone batteries are designed to hold at least 80% of the original capacity for a high number of charge cycles, which varies depending on the product</a>.</p>
<p>While the battery’s capacity to hold a charge diminishes over time, you don’t get to charge to a lower battery percentage, that’s why some people believe their battery is completely fine. But here’s the thing: a new battery will hold much more charge at 100% than an old worn out battery. It’s 100% from the capacity of the battery that is still left which is decreasing a bit with every charge. Let’s say that you have a 3000 mAh battery. When charged 100% it will be close to 3000 mAh. In time, the battery capacity will wear out and instead of 3000 mAh, it will hold only 1600 mAh (for example). You will still see that your phone has charged to 100%, but 100% now means 1600 mAh, not 3000 mAh as it was the case when the battery was new. That’s why it lasts less.</p>
<p>There are multiple factors that contribute to the wearing of the battery, including keeping the battery in high state of charge, keeping the charger plugged in all the times, using battery-draining apps / tweaks (because it makes you charge much often and you lose battery capacity with every charge cycle) and even operating the battery at low or high temperatures. Lithium batteries are very easily damaged.</p>
<h3 id="should-i-jailbreak-if-my-battery-is-already-holding-considerably-less-charge-than-when-it-was-new">Should I jailbreak if my battery is already holding considerably less charge than when it was new?</h3>
<p>That’s entirely up to you, but if you have an already worn out battery (for example you’ve had your phone for 3 years and you’ve been using it daily), you should keep in mind that jailbreaking will only make matters a bit worse. While many tweaks do not consume a ton of power, many interesting ones like <code class="high">Anemone 2</code> (for theming) would. Add that to the already worn out battery and sprinkle a bit of cellular data connection and you’ll suddenly realize that you won’t make it through the day without a portable charger. Should you stop jailbreaking? Not necessarily, but I’d be more cautious on what I install and I’d avoid battery hogs like lockscreens, widgets or <code class="high">Anemone 2</code>.</p>
<h3 id="how-can-i-tell-if-tweaks-draw-more-battery-on-my-setup">How can I tell if tweaks draw more battery on my setup?</h3>
<p>A common way to do this is to use the command <code class="high">top -o cpu</code> via <code class="high">SSH</code> or using NewTerm2. It will show up which daemons or processes hog the CPU and thus drain the battery quicker. On my setup with all tweaks disabled the <code class="high">backboardd</code> daemon for example runs at about 16-20%. With all the tweaks enabled it hogs the CPU to about 63-68% that is much more. In my setup <code class="high">XenHTML</code> causes the biggest battery drain followed by <code class="high">Anemone 2</code> and <code class="high">Activator</code>.</p>
<h3 id="conclusions">Conclusions</h3>
<p>While jailbreaking is fun and gives you enormous power over your device, with great power comes great responsibility. It’s not possible to have no additional battery consumption if you are jailbroken compared to if you’re stock, and the amount of extra battery draining you’ll see depends on multiple factors such as the number of tweaks you’ve installed, how much you use the phone, if you use tethering and mobile data, if you use graphically-intensive tweaks, the battery wear level and the quality of the jailbreak. That doesn’t mean you should not jailbreak your device. It just means you should be careful what you install and you should always assess your battery health in <code class="high">Settings > Battery > Battery Health</code>.</p>
<p>Remember that when you are jailbroken you add more processes and more resource eating tasks on top of the stock iOS ones so there will be more battery draining. For some people with new devices and good batteries the draining may not be very noticeable, but the older the battery is, the more you’ll feel the diminished capacity to hold the charge.</p>
<h3 id="contact">Contact</h3>
<ul>
<li>Twitter: <a href="https://twitter.com/FCE365">GeoSn0w</a></li>
</ul>Recently I got in a heated discussion with a friend about tweaks and how a seemingly benign tweak that does nothing but to change a .plist file can actually become a vector for serious battery draining. While discussing with the person about TetherMe, a tweak which unlocks the cellular data tethering, in the context of battery drain, I realized that some people only see one single dimension of a specific action which could potentially be a problem when you install tweaks. Let’s dive a bit into the idea of batter draining in the context of jailbreak tweaks.A long evening with iOS and macOS Sandbox2018-12-27T00:00:00+00:002018-12-27T00:00:00+00:00https://geosn0w.github.io/A-Long-Evening-With-macOS's-Sandbox<p>Hi there! It’s GeoSn0w. The macOS Sandbox has always been a mysterious thing that I liked to poke at with various tools and with the knowledge I have gathered from reference books such as Jonathan Levin’s *OS Internals, and Apple’s own not-so-detailed documentation. Of course, it’s nothing new that Apple’s documentation on their own security mechanisms isn’t the best. The Sandbox has a very long history and it’s been with us, macOS users for quite a long time, only to spin off to iOS and the rest of the *OSes and to become more powerful over time. Apple’s been doing their darn best to harden the Sandbox as well as many other security mechanisms in their operating systems, so let’s grab a cup of coffee and dive a bit into the marvel that is the macOS Sandbox.</p>
<h3 id="a-bit-of-historical-value">A bit of historical value</h3>
<p>The Sandbox is definitely not new. It’s been first introduced in OS X 10.5 “Leopard”, many, many moons ago, and it was called “SeatBelt”. The idea was simple, just like you buckle your seatbelt to be safe on a car journey, the developer should voluntarily enforce the sandbox upon their applications to restrict their access to the system. As you can probably imagine, not many developers did this, and since the initial concept of the “SeatBelt” was voluntary confinement, Apple couldn’t do much. Paired with the <code class="high">MandatoryAccessControl (MAC) Framework</code>, the idea of Sandbox was definitely not bad, but nowhere near successful. The MACF framework is pretty much the foundation on top of which the entire security model of the Apple devices is built.</p>
<p>Enter OS X 10.7. With Apple having learned their lesson, SandBox evolves now to no longer depend on the developer to enforce it upon their apps, it is enforced by default. Thing is, Apple enforces the SandBox, even as of today on macOS Mojave, based on an entitlement the applications own, which is <code class="high">com.apple.security.app-sandbox</code>. If the application has this entitlement, it will be placed in a container regardless of the wish of the developer. To be frank, developer’s opinion is kinda moot anyway, because applications uploaded into the macOS App Store are signed by Apple and during the signing process, Apple graciously slaps the Sandbox entitlement on the application thus forcing the containerization of any App Store application.</p>
<p>An important aspect to keep in mind is that compared to iOS’ Sandbox, macOS has it easier. See, on iOS, there is no way for you, a third party app developer to ever escape your Sandbox unless you use a Sandbox escape technique, most of the times powered by a Kernel exploit or a Sandbox escape exploit. All 3rd-party applications, regardless of where they’ve been installed / side-loaded from, are placed on iOS in <code class="high">/var/mobile/Containers</code> and <code class="high">/var/Containers</code>. These paths have changed a lot beginning with iOS 8 when new folders were created and things were moved around to separate App resources, static from runtime data, so on older iOS, you may find the apps installed in <code class="high">/var/mobile/Applications</code> or even <code class="high">/var/mobile/Containers/Bundle/</code>. It doesn’t matter. Anything in <code class="high">/var/</code> is destined to be Sandboxed and there is no way around it because you cannot just install your app elsewhere, unless you Jailbreak the device, of course. On macOS, only App Store apps are guaranteed to be sandboxed. If you get an application in a DMG image from a developer website (which is extremely common), it is very likely not sandboxed.</p>
<h3 id="but-what-exactly-is-the-sandbox-doing-anyways">But what exactly is the Sandbox doing anyways?</h3>
<p>The Sandbox’ sole purpose is to restrict applications from accessing various resources of the system. This can be either syscalls, files or whatever. It’s pretty much put in place to do damage control. See, on iOS for example, if you’re gullible enough, I can trick you into installing a malicious application, but it would be pointless because unless I go out of my way to use a Kernel or Sandbox escape exploit (which are usually not available for the latest iOS version), then my application cannot do much harm to your device. If I want to be a complete dick and remove some important files from your phone to make it never boot again, I cannot. Stock iOS enforces the Sandbox amongst other protections against unauthorized access, so my application will have access to nothing but its own container in which it cannot do much damage. The app may still be able to collect some data or do some nasty stuff, but nowhere near the imminent death it could have caused to the system had it had unfettered access. The same thing applies to macOS App Store apps, but not for apps that come in DMG format which are likely not sandboxed.</p>
<p>The Sandbox is actually a very good idea, that’s probably why it stuck with Apple to the present day. Imagine Windows. I can trick you fairly easy to open a program you downloaded from a shady source and that program will graciously delete the <code class="high">System32</code> folder or other important files. Why? Because there is no Sandbox in place on Windows. Yes, some resources need the user to confirm they want to open a program in “Administrator mode”, thus elevating the privileges, but it has become second nature to many people to just press “Run”, so it won’t protect much.</p>
<p>Apple puts it simply: Sandbox is an access control technology enforced at kernel level (where you, the user, or any compromised app from whatever source wouldn’t normally have control). The Sandbox pretty much ensures that it hocks (intercepts) all operations done by the sandboxed application and forbids access to resources the app is not given access to. You can imagine throwing your app in a jail cell and watching its every step.</p>
<p>On macOS, the Sandbox itself is not a single file or a single process, it is split into multiple components that work together to create the Sandbox. At first, we have the <code class="high">userland daemon</code> located in <code class="high">/usr/libexec/sandboxd</code>, there is the <code class="high">com.apple.security.sandbox</code> which is a <code class="high">kext (Kernel Extension)</code>, and there’s also the <code class="high">AppSandbox</code> private framework which relies on <code class="high">AppContainer.Framework</code>. As you can see, multiple components work together to implement what we call the <code class="high">App Sandbox</code>.</p>
<p>You can see the kext being active on macOS by running the <code class="high">kextstat | grep "sand"</code> command in Terminal.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Isabella:/ geosn0w<span class="nv">$ </span>kextstat | <span class="nb">grep</span> <span class="s2">"sand"</span>
38 1 0xffffff7f811a3000 0x21000 0x21000 com.apple.security.sandbox <span class="o">(</span>300.0<span class="o">)</span> BDFF700A-6746-3643-A0A1-852628695B04 <37 30 18 7 6 5 4 3 2 1>
Isabella:/ geosn0w<span class="nv">$ </span>
</code></pre></div></div>
<p>The Sandbox is one of the multiple <code class="high">MACF Policy modules</code>. The <code class="high">CodeSign</code> enforced by <code class="high">AMFI (Apple Mobile File Integrity)</code> is another module.</p>
<h3 id="experiment-determining-whether-an-app-on-macos-is-sandboxed-or-not-based-on-its-entitlements">Experiment: Determining whether an app on macOS is sandboxed or not based on its entitlements</h3>
<p>As I mentioned earlier, a telltale sign that the app is sandboxed, is the presence of <code class="high">com.apple.security.app-sandbox</code> entitlement in the application binary. We can check the entitlements on macOS using multiple tools, but my favorite is <code class="high">jtool</code> by Jonathan Levin. By running the command <code class="high">./jtool --ent /Applications/AppName.app</code> in Terminal, we can see the full list of entitlements that the application possesses. Let’s try it with iHex, an app I got from the macOS App Store, and then with OpenBoardView - an app downloaded in DMG format.</p>
<p>Running the command in Terminal yields the following result for iHex:</p>
<p align="center">
<img src="https://user-images.githubusercontent.com/15067741/50491344-d3f64580-09df-11e9-9094-39fa79c6fed7.png" />
</p>
<p>Alright, so, a few things demand an explanation here. At first, as you can see, the entitlement is present and the key is set to <code class="high">true</code>. This application will be Sandboxed. Now, as you could see, these entitlements are listed in a format akin to XML. That is because they’re actually in a <code class="high">.PLIST or Property List</code> file which is nothing but a glorified XML. PLISTs can, however, come in binary format, but one can easily convert them in the human-readable format by using the command <code class="high">plutil -convert xml1 -o</code>.</p>
<p>Using <code class="high">Jtool</code>, one can easily replace the entitlements of the application but that requires fake-signing the app. All in all, this is a method to unsandbox a macOS application. This cannot be easily done on iOS because the sandboxing there is based on the location where the app is installed and not solely on the possession of an entitlement.</p>
<p>Let’s now take a look at OpenBoardView, an app that wasn’t downloaded from the App Store.</p>
<p align="center">
<img src="https://user-images.githubusercontent.com/15067741/50491825-4700bb80-09e2-11e9-887e-2fcef1260437.png" />
</p>
<p>As you can see, the application has no entitlements whatsoever. It will not be sandboxed and this means that it can access way more sources than any App Store application. We can inject the sandbox entitlement into it with <code class="high">jtool</code>, but the point is, yes, non-App Store apps are, indeed, more dangerous.</p>
<p>Remember, the <code class="high">com.apple.security.app-sandbox</code> entitlement was not added by the developer of the iHEX application, it was added automatically by Apple in the process of signing when the application got published in the App Store and there is nothing the developer could do to remove the entitlement, other than distributing their app via other means. Normally the entitlements tell what your application CAN do. In the case of this entitlement, it pretty much limits the application heavily from accessing system resources or user data.</p>
<p>Another way of checking whether the application is sandboxed or not is to run the command <code class="high">asctl sandbox check --pid XYZ</code> where XYZ is the <code class="high">PID (Process ID)</code> of the application you’re interested in. You can get the <code class="high">PID</code> of a running process from the <code class="high">Activity Monitor</code> application on macOS. Here’s the output of the <code class="high">asctl</code> command.</p>
<p align="center">
<img src="https://user-images.githubusercontent.com/15067741/50493572-58e75c00-09ec-11e9-87f5-4ab9d05fcf54.png" />
</p>
<h3 id="how-is-the-sandbox-enforced">How is the Sandbox enforced?</h3>
<p>Okay, we established what the Sandbox is, how you know you are sandboxed and why you are sandboxed in the first place, but what exactly happens when a sandboxed application runs?</p>
<p>Enter containers. A container is pretty much just a folder placed on <code class="high">$HOME/Library/Containers/</code>. This folder is created for any sandboxed application regardless of the place the actual binary is installed on. The folder follow a simple structure, but most importantly, it contains a <code class="high">Container.Plist</code> file which contains information about the application whose Container this is (identified by its <code class="high">CFBundleIdentifier</code>), the <code class="high">SandboxProfileData</code>, the <code class="high">SandboxProfileDataValidationInfo</code> and the <code class="high">Version</code> of the Sandbox.</p>
<p>Let’s find iHEX’ Container.
We can easily do that by changing directory (cd) to the path mentioned above, and then running <code class="high">ls -lF com.hewbo.hexeditor</code>. Where <code class="high">com.hewbo.hexeditor</code> is the <code class="high">CFBundleIndentifier</code> of the iHex app (you can find it in the <code class="high">Info.Plist</code> inside the .app folder).</p>
<p align="center">
<img src="https://user-images.githubusercontent.com/15067741/50492230-757f9600-09e4-11e9-94a3-21fa6aafc812.png" />
</p>
<p>Okay, so you can see that the container of the app contains a <code class="high">Data</code> folder as well as the aforementioned Container.Plist file. The Data folder is very interesting. If you change directory (cd) into it you can see that it simulates the user’s Home directory. Of course, all of those are tightly controlled symlinks. The control is being enforced by the Container.plist which contains the <code class="high">SandboxProfileDataValidationRedirectablePathsKey</code> that dictates which symlinks are approved.</p>
<p align="center">
<img src="https://user-images.githubusercontent.com/15067741/50492397-58979280-09e5-11e9-8cb6-dc964d24819e.png" />
</p>
<h3 id="sandboxed-from-moment-one">Sandboxed from moment one</h3>
<p>When you start an application, internally, the Kernel will get to call the function <code class="high">mac_execve</code>, which can be seen in the XNU source code. The <code class="high">__mac_execve</code> will pretty much load the binary but it will also check the <code class="high">MAC label</code> to see whether Sandbox should be enforced. At this point, the system is aware that you are going to be Sandboxed but you’re not just yet.</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/*
* __mac_execve
*
* Parameters: uap->fname File name to exec
* uap->argp Argument list
* uap->envp Environment list
* uap->mac_p MAC label supplied by caller
*
* Returns: 0 Success
* EINVAL Invalid argument
* ENOTSUP Not supported
* ENOEXEC Executable file format error
* exec_activate_image:EINVAL Invalid argument
* exec_activate_image:EACCES Permission denied
* exec_activate_image:EINTR Interrupted function
* exec_activate_image:ENOMEM Not enough space
* exec_activate_image:EFAULT Bad address
* exec_activate_image:ENAMETOOLONG Filename too long
* exec_activate_image:ENOEXEC Executable file format error
* exec_activate_image:ETXTBSY Text file busy [misuse of error code]
* exec_activate_image:EBADEXEC The executable is corrupt/unknown
* exec_activate_image:???
* mac_execve_enter:???
*
* TODO: Dynamic linker header address on stack is copied via suword()
*/</span>
<span class="kt">int</span>
<span class="nf">__mac_execve</span><span class="p">(</span><span class="n">proc_t</span> <span class="n">p</span><span class="p">,</span> <span class="k">struct</span> <span class="n">__mac_execve_args</span> <span class="o">*</span><span class="n">uap</span><span class="p">,</span> <span class="kt">int32_t</span> <span class="o">*</span><span class="n">retval</span><span class="p">)</span>
<span class="p">{</span>
<span class="kt">char</span> <span class="o">*</span><span class="n">bufp</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
<span class="k">struct</span> <span class="n">image_params</span> <span class="o">*</span><span class="n">imgp</span><span class="p">;</span>
<span class="k">struct</span> <span class="n">vnode_attr</span> <span class="o">*</span><span class="n">vap</span><span class="p">;</span>
<span class="k">struct</span> <span class="n">vnode_attr</span> <span class="o">*</span><span class="n">origvap</span><span class="p">;</span>
<span class="kt">int</span> <span class="n">error</span><span class="p">;</span>
<span class="kt">char</span> <span class="n">alt_p_comm</span><span class="p">[</span><span class="k">sizeof</span><span class="p">(</span><span class="n">p</span><span class="o">-></span><span class="n">p_comm</span><span class="p">)]</span> <span class="o">=</span> <span class="p">{</span><span class="mi">0</span><span class="p">};</span> <span class="cm">/* for PowerPC */</span>
<span class="kt">int</span> <span class="n">is_64</span> <span class="o">=</span> <span class="n">IS_64BIT_PROCESS</span><span class="p">(</span><span class="n">p</span><span class="p">);</span>
<span class="k">struct</span> <span class="n">vfs_context</span> <span class="n">context</span><span class="p">;</span>
<span class="n">context</span><span class="p">.</span><span class="n">vc_thread</span> <span class="o">=</span> <span class="n">current_thread</span><span class="p">();</span>
<span class="n">context</span><span class="p">.</span><span class="n">vc_ucred</span> <span class="o">=</span> <span class="n">kauth_cred_proc_ref</span><span class="p">(</span><span class="n">p</span><span class="p">);</span> <span class="cm">/* XXX must NOT be kauth_cred_get() */</span>
<span class="cm">/* Allocate a big chunk for locals instead of using stack since these
* structures a pretty big.
*/</span>
<span class="n">MALLOC</span><span class="p">(</span><span class="n">bufp</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="p">,</span> <span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="o">*</span><span class="n">imgp</span><span class="p">)</span> <span class="o">+</span> <span class="k">sizeof</span><span class="p">(</span><span class="o">*</span><span class="n">vap</span><span class="p">)</span> <span class="o">+</span> <span class="k">sizeof</span><span class="p">(</span><span class="o">*</span><span class="n">origvap</span><span class="p">)),</span> <span class="n">M_TEMP</span><span class="p">,</span> <span class="n">M_WAITOK</span> <span class="o">|</span> <span class="n">M_ZERO</span><span class="p">);</span>
<span class="n">imgp</span> <span class="o">=</span> <span class="p">(</span><span class="k">struct</span> <span class="n">image_params</span> <span class="o">*</span><span class="p">)</span> <span class="n">bufp</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="n">bufp</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span>
<span class="n">error</span> <span class="o">=</span> <span class="n">ENOMEM</span><span class="p">;</span>
<span class="k">goto</span> <span class="n">exit_with_error</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">vap</span> <span class="o">=</span> <span class="p">(</span><span class="k">struct</span> <span class="n">vnode_attr</span> <span class="o">*</span><span class="p">)</span> <span class="p">(</span><span class="n">bufp</span> <span class="o">+</span> <span class="k">sizeof</span><span class="p">(</span><span class="o">*</span><span class="n">imgp</span><span class="p">));</span>
<span class="n">origvap</span> <span class="o">=</span> <span class="p">(</span><span class="k">struct</span> <span class="n">vnode_attr</span> <span class="o">*</span><span class="p">)</span> <span class="p">(</span><span class="n">bufp</span> <span class="o">+</span> <span class="k">sizeof</span><span class="p">(</span><span class="o">*</span><span class="n">imgp</span><span class="p">)</span> <span class="o">+</span> <span class="k">sizeof</span><span class="p">(</span><span class="o">*</span><span class="n">vap</span><span class="p">));</span>
<span class="cm">/* Initialize the common data in the image_params structure */</span>
<span class="n">imgp</span><span class="o">-></span><span class="n">ip_user_fname</span> <span class="o">=</span> <span class="n">uap</span><span class="o">-></span><span class="n">fname</span><span class="p">;</span>
<span class="n">imgp</span><span class="o">-></span><span class="n">ip_user_argv</span> <span class="o">=</span> <span class="n">uap</span><span class="o">-></span><span class="n">argp</span><span class="p">;</span>
<span class="n">imgp</span><span class="o">-></span><span class="n">ip_user_envv</span> <span class="o">=</span> <span class="n">uap</span><span class="o">-></span><span class="n">envp</span><span class="p">;</span>
<span class="n">imgp</span><span class="o">-></span><span class="n">ip_vattr</span> <span class="o">=</span> <span class="n">vap</span><span class="p">;</span>
<span class="n">imgp</span><span class="o">-></span><span class="n">ip_origvattr</span> <span class="o">=</span> <span class="n">origvap</span><span class="p">;</span>
<span class="n">imgp</span><span class="o">-></span><span class="n">ip_vfs_context</span> <span class="o">=</span> <span class="o">&</span><span class="n">context</span><span class="p">;</span>
<span class="n">imgp</span><span class="o">-></span><span class="n">ip_flags</span> <span class="o">=</span> <span class="p">(</span><span class="n">is_64</span> <span class="o">?</span> <span class="n">IMGPF_WAS_64BIT</span> <span class="o">:</span> <span class="n">IMGPF_NONE</span><span class="p">)</span> <span class="o">|</span> <span class="p">((</span><span class="n">p</span><span class="o">-></span><span class="n">p_flag</span> <span class="o">&</span> <span class="n">P_DISABLE_ASLR</span><span class="p">)</span> <span class="o">?</span> <span class="n">IMGPF_DISABLE_ASLR</span> <span class="o">:</span> <span class="n">IMGPF_NONE</span><span class="p">);</span>
<span class="n">imgp</span><span class="o">-></span><span class="n">ip_p_comm</span> <span class="o">=</span> <span class="n">alt_p_comm</span><span class="p">;</span> <span class="cm">/* for PowerPC */</span>
<span class="n">imgp</span><span class="o">-></span><span class="n">ip_seg</span> <span class="o">=</span> <span class="p">(</span><span class="n">is_64</span> <span class="o">?</span> <span class="n">UIO_USERSPACE64</span> <span class="o">:</span> <span class="n">UIO_USERSPACE32</span><span class="p">);</span>
<span class="cp">#if CONFIG_MACF
</span> <span class="k">if</span> <span class="p">(</span><span class="n">uap</span><span class="o">-></span><span class="n">mac_p</span> <span class="o">!=</span> <span class="n">USER_ADDR_NULL</span><span class="p">)</span> <span class="p">{</span>
<span class="n">error</span> <span class="o">=</span> <span class="n">mac_execve_enter</span><span class="p">(</span><span class="n">uap</span><span class="o">-></span><span class="n">mac_p</span><span class="p">,</span> <span class="n">imgp</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">error</span><span class="p">)</span> <span class="p">{</span>
<span class="n">kauth_cred_unref</span><span class="p">(</span><span class="o">&</span><span class="n">context</span><span class="p">.</span><span class="n">vc_ucred</span><span class="p">);</span>
<span class="k">goto</span> <span class="n">exit_with_error</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="cp">#endif
</span>
<span class="n">error</span> <span class="o">=</span> <span class="n">exec_activate_image</span><span class="p">(</span><span class="n">imgp</span><span class="p">);</span>
<span class="n">kauth_cred_unref</span><span class="p">(</span><span class="o">&</span><span class="n">context</span><span class="p">.</span><span class="n">vc_ucred</span><span class="p">);</span>
<span class="cm">/* Image not claimed by any activator? */</span>
<span class="k">if</span> <span class="p">(</span><span class="n">error</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span>
<span class="n">error</span> <span class="o">=</span> <span class="n">ENOEXEC</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="n">error</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
<span class="n">exec_resettextvp</span><span class="p">(</span><span class="n">p</span><span class="p">,</span> <span class="n">imgp</span><span class="p">);</span>
<span class="n">error</span> <span class="o">=</span> <span class="n">check_for_signature</span><span class="p">(</span><span class="n">p</span><span class="p">,</span> <span class="n">imgp</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="n">imgp</span><span class="o">-></span><span class="n">ip_vp</span> <span class="o">!=</span> <span class="n">NULLVP</span><span class="p">)</span>
<span class="n">vnode_put</span><span class="p">(</span><span class="n">imgp</span><span class="o">-></span><span class="n">ip_vp</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">imgp</span><span class="o">-></span><span class="n">ip_strings</span><span class="p">)</span>
<span class="n">execargs_free</span><span class="p">(</span><span class="n">imgp</span><span class="p">);</span>
<span class="cp">#if CONFIG_MACF
</span> <span class="k">if</span> <span class="p">(</span><span class="n">imgp</span><span class="o">-></span><span class="n">ip_execlabelp</span><span class="p">)</span>
<span class="n">mac_cred_label_free</span><span class="p">(</span><span class="n">imgp</span><span class="o">-></span><span class="n">ip_execlabelp</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">imgp</span><span class="o">-></span><span class="n">ip_scriptlabelp</span><span class="p">)</span>
<span class="n">mac_vnode_label_free</span><span class="p">(</span><span class="n">imgp</span><span class="o">-></span><span class="n">ip_scriptlabelp</span><span class="p">);</span>
<span class="cp">#endif
</span> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">error</span><span class="p">)</span> <span class="p">{</span>
<span class="k">struct</span> <span class="n">uthread</span> <span class="o">*</span><span class="n">uthread</span><span class="p">;</span>
<span class="cm">/* Sever any extant thread affinity */</span>
<span class="n">thread_affinity_exec</span><span class="p">(</span><span class="n">current_thread</span><span class="p">());</span>
<span class="n">DTRACE_PROC</span><span class="p">(</span><span class="n">exec__success</span><span class="p">);</span>
<span class="n">uthread</span> <span class="o">=</span> <span class="n">get_bsdthread_info</span><span class="p">(</span><span class="n">current_thread</span><span class="p">());</span>
<span class="k">if</span> <span class="p">(</span><span class="n">uthread</span><span class="o">-></span><span class="n">uu_flag</span> <span class="o">&</span> <span class="n">UT_VFORK</span><span class="p">)</span> <span class="p">{</span>
<span class="n">vfork_return</span><span class="p">(</span><span class="n">p</span><span class="p">,</span> <span class="n">retval</span><span class="p">,</span> <span class="n">p</span><span class="o">-></span><span class="n">p_pid</span><span class="p">);</span>
<span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">thread_resume</span><span class="p">(</span><span class="n">imgp</span><span class="o">-></span><span class="n">ip_new_thread</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="n">DTRACE_PROC1</span><span class="p">(</span><span class="n">exec__failure</span><span class="p">,</span> <span class="kt">int</span><span class="p">,</span> <span class="n">error</span><span class="p">);</span>
<span class="p">}</span>
<span class="nl">exit_with_error:</span>
<span class="k">if</span> <span class="p">(</span><span class="n">bufp</span> <span class="o">!=</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span>
<span class="n">FREE</span><span class="p">(</span><span class="n">bufp</span><span class="p">,</span> <span class="n">M_TEMP</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">return</span><span class="p">(</span><span class="n">error</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>
<p>When the process starts, quite eraly in its lifetime it will load <code class="high">libSystem.B</code> because all the APIs rely on it. At some point during the execution, <code class="high">libSystem.B.initializer</code> will fall to <code class="high">_libsecinit_setup_secinitd_client</code> which will then fall to <code class="high">xpc_copy_entitlements_for_pid</code> to grab the Entitlements from the application binary, and then it will send the entitlements as well as whether the application is supposed to be sandboxed via an XPC message to <code class="high">secinitd</code> daemon located in <code class="high">/usr/libexec/secinitd</code>. This message transfer happens at <code class="high">xpc_pipe_route</code> level. The same function will handle the message receive from the <code class="high">secinitd</code> daemon which will parse the XPC message received from the process.</p>
<p>The <code class="high">secinitd</code> dameon will acknowledge the fact that sandboxing should be enforced if the entitlement is present, then it will call upon the <code class="high">AppSandbox.Framework</code> to create the <code class="high">sandbox profile</code>. After the profile is created <code class="high">secinitd</code> will return an <code class="high">XPC message</code> containing the <code class="high">CONTAINER_ID_KEY, CONTAINER_ROOT_PATH_KEY, SANDBOX_PROFILE_DATA_KEY</code>, amongst other data. This information will be parsed by <code class="high">_libsecinit_setup_app_sandbox</code> which then falls into <code class="high">__sandbox_ms</code> thus creating the sandbox of the application and containerizing it at runtime.</p>
<p>Since this is a pretty confusing explanation, thanks to a diagram made by Jonathan Levin (Figure 8-4) in *OS Internals Volume III, I managed to create my own version of the diagram which is a bit more simplified but should suffice. Huge thanks to Jonathan for his research, it is him who put together the research material I used to understand how the Sandbox works.</p>
<p align="center">
<img src="https://user-images.githubusercontent.com/15067741/50495021-9a7c0500-09f4-11e9-9050-72792ceda700.png" />
</p>
<h3 id="experiment-tracing-the-app-sandbox-as-it-is-being-created-at-runtime">Experiment: Tracing the App Sandbox as it is being created at runtime</h3>
<p>So, now that we have an idea of how the Sandbox works, let’s see it in action. Using LLDB we can debug a sandboxed application and see exactly what is going on, down to the XPC messages being passed over from the process to <code class="high">secinitd</code> daemon. We’re about to dive into Terminal and LLDB, so the following listing may appear very hard to follow. To make it easier on yourself to understand what is going on, it’s best to try to follow the important logic like the messages being passed around and the backtrace to see what function calls we do.</p>
<p>At first, we start by opening the Terminal and calling lldb. If you don’t have LLDB installed, install Xcode as it comes with all the debugging tools you need.
First, we start by setting a few break points. We’re doing to break at <code class="high">xpc_pipe_routine</code> where the XPC messages are sent and received, and at <code class="high">__sandbox_ms</code> which is the Sandbox MACF syscall.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Last login: Thu Dec 27 16:44:59 on ttys000
Isabella:~ geosn0w<span class="nv">$ </span>lldb /Applications/iHex.app/Contents/MacOS/iHex
<span class="o">(</span>lldb<span class="o">)</span> target create <span class="s2">"/Applications/iHex.app/Contents/MacOS/iHex"</span>
Traceback <span class="o">(</span>most recent call last<span class="o">)</span>:
File <span class="s2">"<string>"</span>, line 1, <span class="k">in</span> <module>
File <span class="s2">"/Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Resources/Python/lldb/__init__.py"</span>, line 98, <span class="k">in</span> <module>
import six
ImportError: No module named six
Traceback <span class="o">(</span>most recent call last<span class="o">)</span>:
File <span class="s2">"<string>"</span>, line 1, <span class="k">in</span> <module>
NameError: name <span class="s1">'run_one_line'</span> is not defined
Traceback <span class="o">(</span>most recent call last<span class="o">)</span>:
File <span class="s2">"<string>"</span>, line 1, <span class="k">in</span> <module>
Current executable <span class="nb">set </span>to <span class="s1">'/Applications/iHex.app/Contents/MacOS/iHex'</span> <span class="o">(</span>x86_64<span class="o">)</span><span class="nb">.</span>
<span class="o">(</span>lldb<span class="o">)</span> b xpc_pipe_routine
Breakpoint 1: where <span class="o">=</span> libxpc.dylib<span class="sb">`</span>xpc_pipe_routine, address <span class="o">=</span> 0x0000000000005c40
<span class="o">(</span>lldb<span class="o">)</span> b __sandbox_ms
Breakpoint 2: where <span class="o">=</span> libsystem_kernel.dylib<span class="sb">`</span>__mac_syscall, address <span class="o">=</span> 0x000000000001c648
<span class="o">(</span>lldb<span class="o">)</span> run
Process 12594 stopped
<span class="k">*</span> thread <span class="c">#1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1</span>
frame <span class="c">#0: 0x00007fff6a75ec40 libxpc.dylib`xpc_pipe_routine</span>
libxpc.dylib<span class="sb">`</span>xpc_pipe_routine:
-> 0x7fff6a75ec40 <+0>: pushq %rbp
0x7fff6a75ec41 <+1>: movq %rsp, %rbp
0x7fff6a75ec44 <+4>: pushq %r15
0x7fff6a75ec46 <+6>: pushq %r14
Target 0: <span class="o">(</span>iHex<span class="o">)</span> stopped.
<span class="o">(</span>lldb<span class="o">)</span> c
Process 12594 resuming
Process 12594 stopped
<span class="k">*</span> thread <span class="c">#1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1</span>
frame <span class="c">#0: 0x00007fff6a75ec40 libxpc.dylib`xpc_pipe_routine</span>
libxpc.dylib<span class="sb">`</span>xpc_pipe_routine:
-> 0x7fff6a75ec40 <+0>: pushq %rbp
0x7fff6a75ec41 <+1>: movq %rsp, %rbp
0x7fff6a75ec44 <+4>: pushq %r15
0x7fff6a75ec46 <+6>: pushq %r14
Target 0: <span class="o">(</span>iHex<span class="o">)</span> stopped.
</code></pre></div></div>
<p>All fine and well, our breakpoints worked and we are now in <code class="high">libxpc.dylib</code> and we stopped at the <code class="high">xpc_pipe_routine</code>. Let’s do a <code class="high">backtrace</code> to see what is going on. We can do that with the <code class="high">bt</code> command.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">(</span>lldb<span class="o">)</span> bt
<span class="k">*</span> thread <span class="c">#1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1</span>
<span class="k">*</span> frame <span class="c">#0: 0x00007fff6a75ec40 libxpc.dylib`xpc_pipe_routine</span>
frame <span class="c">#1: 0x00007fff6a75eaad libxpc.dylib`_xpc_interface_routine + 167</span>
frame <span class="c">#2: 0x00007fff6a7650b5 libxpc.dylib`_xpc_uncork_domain + 529</span>
frame <span class="c">#3: 0x00007fff6a75ad85 libxpc.dylib`_libxpc_initializer + 1053</span>
frame <span class="c">#4: 0x00007fff680aa9c8 libSystem.B.dylib`libSystem_initializer + 126</span>
frame <span class="c">#5: 0x0000000100582ac6 dyld`ImageLoaderMachO::doModInitFunctions(ImageLoader::LinkContext const&) + 420</span>
frame <span class="c">#6: 0x0000000100582cf6 dyld`ImageLoaderMachO::doInitialization(ImageLoader::LinkContext const&) + 40</span>
...
frame <span class="c">#18: 0x000000010056d3d4 dyld`dyldbootstrap::start(macho_header const*, int, char const**, long, macho_header const*, unsigned long*) + 453</span>
frame <span class="c">#19: 0x000000010056d1d2 dyld`_dyld_start + 54</span>
<span class="o">(</span>lldb<span class="o">)</span> c
Process 12594 resuming
Process 12594 stopped
<span class="k">*</span> thread <span class="c">#1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1</span>
frame <span class="c">#0: 0x00007fff6a75ec40 libxpc.dylib`xpc_pipe_routine</span>
libxpc.dylib<span class="sb">`</span>xpc_pipe_routine:
-> 0x7fff6a75ec40 <+0>: pushq %rbp
0x7fff6a75ec41 <+1>: movq %rsp, %rbp
0x7fff6a75ec44 <+4>: pushq %r15
0x7fff6a75ec46 <+6>: pushq %r14
Target 0: <span class="o">(</span>iHex<span class="o">)</span> stopped.
</code></pre></div></div>
<p>Nope, not what we need. This is the <code class="high">_xpc_uncork_domain</code> function of <code class="high">libxpc.dylib</code>. We need the <code class="high">xpc_pipe_create</code> one. We press <code class="high">c</code> to continue and backtrace again.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">(</span>lldb<span class="o">)</span> bt
<span class="k">*</span> thread <span class="c">#1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1</span>
<span class="k">*</span> frame <span class="c">#0: 0x00007fff6a75ec40 libxpc.dylib`xpc_pipe_routine</span>
frame <span class="c">#1: 0x00007fff6a75eaad libxpc.dylib`_xpc_interface_routine + 167</span>
frame <span class="c">#2: 0x00007fff6a75e5d3 libxpc.dylib`bootstrap_look_up3 + 185</span>
frame <span class="c">#3: 0x00007fff6a75e4ff libxpc.dylib`bootstrap_look_up2 + 41</span>
frame <span class="c">#4: 0x00007fff6a7609d7 libxpc.dylib`xpc_pipe_create + 60</span>
frame <span class="c">#5: 0x00007fff6a500485 libsystem_info.dylib`_mbr_xpc_pipe + 261</span>
frame <span class="c">#6: 0x00007fff6a50033f libsystem_info.dylib`_mbr_od_available + 15</span>
frame <span class="c">#7: 0x00007fff6a4fffe5 libsystem_info.dylib`mbr_identifier_translate + 645</span>
frame <span class="c">#8: 0x00007fff6a4ffbf5 libsystem_info.dylib`mbr_identifier_to_uuid + 53</span>
frame <span class="c">#9: 0x00007fff6a4ffbba libsystem_info.dylib`mbr_uid_to_uuid + 42</span>
frame <span class="c">#10: 0x00007fff6a734db4 libsystem_secinit.dylib`_libsecinit_setup_secinitd_client + 728</span>
frame <span class="c">#11: 0x00007fff6a734a7b libsystem_secinit.dylib`_libsecinit_initialize_once + 13</span>
frame <span class="c">#12: 0x00007fff6a3d5db8 libdispatch.dylib`_dispatch_client_callout + 8</span>
frame <span class="c">#13: 0x00007fff6a3d5d6b libdispatch.dylib`dispatch_once_f + 41</span>
frame <span class="c">#14: 0x00007fff680aa9d2 libSystem.B.dylib`libSystem_initializer + 136</span>
....
frame <span class="c">#29: 0x000000010056d1d2 dyld`_dyld_start + 54</span>
</code></pre></div></div>
<p>Yep! We found what we need, the <code class="high">xpc_pipe_create</code> function. Now thanks to Jonathan Levin, I learned that you can use the <code class="high">p (char *) xpc_copy_description($rsi)</code> to view the message that is being sent through the XPC pipe which is super useful for debugging. We use the <code class="high">RSI</code> register as the message is the second argument (the first one is the pipe).</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">(</span>lldb<span class="o">)</span> p <span class="o">(</span>char <span class="k">*</span><span class="o">)</span> xpc_copy_description<span class="o">(</span><span class="nv">$rsi</span><span class="o">)</span>
<span class="o">(</span>char <span class="k">*</span><span class="o">)</span> <span class="nv">$0</span> <span class="o">=</span> 0x0000000101101fa0 <span class="s2">"<dictionary: 0x10100c430> { count = 9, transaction: 0, voucher = 0x0, contents =</span><span class="se">\n\t</span><span class="s2">"</span>subsystem<span class="s2">" => <uint64: 0x10100c7a0>: 5</span><span class="se">\n\t</span><span class="s2">"</span>handle<span class="s2">" => <uint64: 0x10100c540>: 0</span><span class="se">\n\t</span><span class="s2">"</span>instance<span class="s2">" => <uuid: 0x10100c6e0> 00000000-0000-0000-0000-000000000000</span><span class="se">\n\t</span><span class="s2">"</span>routine<span class="s2">" => <uint64: 0x10100c800>: 207</span><span class="se">\n\t</span><span class="s2">"</span>flags<span class="s2">" => <uint64: 0x10100c750>: 8</span><span class="se">\n\t</span><span class="s2">"</span>name<span class="s2">" => <string: 0x10100c620> { length = 42, contents = "</span>com.apple.system.opendirectoryd.membership<span class="s2">" }</span><span class="se">\n\t</span><span class="s2">"</span><span class="nb">type</span><span class="s2">" => <uint64: 0x10100c4f0>: 7</span><span class="se">\n\t</span><span class="s2">"</span>targetpid<span class="s2">" => <int64: 0x10100c680>: 0</span><span class="se">\n\t</span><span class="s2">"</span>domain-port<span class="s2">" => <mach send right: 0x10100c590> { name = 1799, right = send, urefs = 5 }</span><span class="se">\n</span><span class="s2">}"</span>
</code></pre></div></div>
<p>Unfortunately, not what we need. This is just a handshake message. We continue.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">(</span>lldb<span class="o">)</span> c
Process 12594 resuming
Process 12594 stopped
<span class="k">*</span> thread <span class="c">#1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1</span>
frame <span class="c">#0: 0x00007fff6a75ec40 libxpc.dylib`xpc_pipe_routine</span>
libxpc.dylib<span class="sb">`</span>xpc_pipe_routine:
-> 0x7fff6a75ec40 <+0>: pushq %rbp
0x7fff6a75ec41 <+1>: movq %rsp, %rbp
0x7fff6a75ec44 <+4>: pushq %r15
0x7fff6a75ec46 <+6>: pushq %r14
Target 0: <span class="o">(</span>iHex<span class="o">)</span> stopped.
...
<span class="o">(</span>lldb<span class="o">)</span> c
Process 12594 resuming
Process 12594 stopped
<span class="k">*</span> thread <span class="c">#1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1</span>
frame <span class="c">#0: 0x00007fff6a75ec40 libxpc.dylib`xpc_pipe_routine</span>
libxpc.dylib<span class="sb">`</span>xpc_pipe_routine:
-> 0x7fff6a75ec40 <+0>: pushq %rbp
0x7fff6a75ec41 <+1>: movq %rsp, %rbp
0x7fff6a75ec44 <+4>: pushq %r15
0x7fff6a75ec46 <+6>: pushq %r14
Target 0: <span class="o">(</span>iHex<span class="o">)</span> stopped.
<span class="o">(</span>lldb<span class="o">)</span> p <span class="o">(</span>char <span class="k">*</span><span class="o">)</span> xpc_copy_description<span class="o">(</span><span class="nv">$rsi</span><span class="o">)</span>
<span class="o">(</span>char <span class="k">*</span><span class="o">)</span> <span class="nv">$5</span> <span class="o">=</span> 0x0000000102821a00 <span class="s2">"<dictionary: 0x1010051b0> { count = 11, transaction: 0, voucher = 0x0, contents =</span><span class="se">\n\t</span><span class="s2">"</span>SECINITD_REGISTRATION_MESSAGE_SHORT_NAME_KEY<span class="s2">" => <string: 0x10100c2d0> { length = 4, contents = "</span>iHex<span class="s2">" }</span><span class="se">\n\t</span><span class="s2">"</span>SECINITD_REGISTRATION_MESSAGE_IS_SANDBOX_CANDIDATE_KEY<span class="s2">" => <bool: 0x7fffa2befb98>: true</span><span class="se">\n\t</span><span class="s2">"</span>SECINITD_REGISTRATION_MESSAGE_ENTITLEMENTS_DICT_KEY<span class="s2">" => <dictionary: 0x101009690> { count = 6, transaction: 0, voucher = 0x0, contents =</span><span class="se">\n\t\t</span><span class="s2">"</span>com.apple.security.app-sandbox<span class="s2">" => <bool: 0x7fffa2befb98>: true</span><span class="se">\n\t\t</span><span class="s2">"</span>com.apple.application-identifier<span class="s2">" => <string: 0x101009a60> { length = 30, contents = "</span>A9TT2D59XS.com.hewbo.hexeditor<span class="s2">" }</span><span class="se">\n\t\t</span><span class="s2">"</span>com.apple.security.print<span class="s2">" => <bool: 0x7fffa2befb98>: true</span><span class="se">\n\t\t</span><span class="s2">"</span>com.apple.security.files.user-selected.read-write<span class="s2">" => <bool: 0x7fffa2befb98>: true</span><span class="se">\n\t\t</span><span class="s2">"</span>com.apple.developer.team-identifier<span class="s2">" => <string: 0x101002ec0> { length = 10, contents = "</span>A9TT2D59XS<span class="s2">" }</span><span class="se">\n\t\t</span><span class="s2">"</span>com.apple.security.network.client<span class="s2">" => <bool: 0x7fffa2befb98>: true</span><span class="se">\n\t</span><span class="s2">}</span><span class="se">\n\t</span><span class="s2">"</span>SECINITD_REGISTRATION_MESSAGE_LIBRARY_VALIDATION_KEY<span class="s2">" => <bool: 0x7fffa2befbb8>: false</span><span class="se">\n</span><span class="s2">"</span>
<span class="o">(</span>lldb<span class="o">)</span>
</code></pre></div></div>
<p>Aargh! There we go! The precious message containing our application’s entitlements and whether it is a candidate for the sandbox. As you can see, the <code class="high">SECINITD_REGISTRATION_MESSAGE_IS_SANDBOX_CANDIDATE_KEY</code> is set to <code class="high">bool true</code> and we do possess the <code class="high">com.apple.security.app-sandbox</code> entitlement. We’re bound to be sandboxed.</p>
<p>Now that we saw exactly what the process has sent to <code class="high">secinitd</code>, let’s see if the sandbox is being created. For that we’re using the second breakpoint we’ve set, the one on <code class="high">__sandbox_ms</code>. Since the breakpoint is already set, we continue (c) until we hit it.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">(</span>lldb<span class="o">)</span> bt
<span class="k">*</span> thread <span class="c">#1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1</span>
<span class="k">*</span> frame <span class="c">#0: 0x00007fff6a55f648 libsystem_kernel.dylib`__mac_syscall</span>
frame <span class="c">#1: 0x00007fff6a731bc9 libsystem_sandbox.dylib`sandbox_container_path_for_pid + 63</span>
frame <span class="c">#2: 0x00007fff6a4edd0c libsystem_coreservices.dylib`_dirhelper_init + 159</span>
frame <span class="c">#3: 0x00007fff6a71cf00 libsystem_platform.dylib`_os_once + 33</span>
frame <span class="c">#4: 0x00007fff6a4ee754 libsystem_coreservices.dylib`_dirhelper + 1873</span>
frame <span class="c">#5: 0x00007fff6a4604e9 libsystem_c.dylib`confstr + 525</span>
frame <span class="c">#6: 0x00007fff6a7354a5 libsystem_secinit.dylib`_libsecinit_setup_app_sandbox + 474 # As you can see, the Sandbox is set.</span>
frame <span class="c">#7: 0x00007fff6a734a82 libsystem_secinit.dylib`_libsecinit_initialize_once + 20</span>
frame <span class="c">#8: 0x00007fff6a3d5db8 libdispatch.dylib`_dispatch_client_callout + 8</span>
frame <span class="c">#9: 0x00007fff6a3d5d6b libdispatch.dylib`dispatch_once_f + 41</span>
frame <span class="c">#10: 0x00007fff680aa9d2 libSystem.B.dylib`libSystem_initializer + 136</span>
frame <span class="c">#11: 0x0000000100582ac6 dyld`ImageLoaderMachO::doModInitFunctions(ImageLoader::LinkContext const&) + 420</span>
frame <span class="c">#12: 0x0000000100582cf6 dyld`ImageLoaderMachO::doInitialization(ImageLoader::LinkContext const&) + 40</span>
frame <span class="c">#13: 0x000000010057e218 dyld`ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int, char const*, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&) + 330</span>
frame <span class="c">#14: 0x000000010057e1ab dyld`ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int, char const*, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&) + 221</span>
frame <span class="c">#15: 0x000000010057e1ab dyld`ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int, char const*, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&) + 221</span>
frame <span class="c">#16: 0x000000010057e1ab dyld`ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int, char const*, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&) + 221</span>
frame <span class="c">#17: 0x000000010057e1ab dyld`ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int, char const*, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&) + 221</span>
frame <span class="c">#18: 0x000000010057e1ab dyld`ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int, char const*, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&) + 221</span>
frame <span class="c">#19: 0x000000010057e1ab dyld`ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int, char const*, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&) + 221</span>
frame <span class="c">#20: 0x000000010057d34e dyld`ImageLoader::processInitializers(ImageLoader::LinkContext const&, unsigned int, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&) + 134</span>
frame <span class="c">#21: 0x000000010057d3e2 dyld`ImageLoader::runInitializers(ImageLoader::LinkContext const&, ImageLoader::InitializerTimingList&) + 74</span>
frame <span class="c">#22: 0x000000010056e567 dyld`dyld::initializeMainExecutable() + 196</span>
frame <span class="c">#23: 0x0000000100573239 dyld`dyld::_main(macho_header const*, unsigned long, int, char const**, char const**, char const**, unsigned long*) + 7242</span>
frame <span class="c">#24: 0x000000010056d3d4 dyld`dyldbootstrap::start(macho_header const*, int, char const**, long, macho_header const*, unsigned long*) + 453</span>
frame <span class="c">#25: 0x000000010056d1d2 dyld`_dyld_start + 54</span>
<span class="o">(</span>lldb<span class="o">)</span>
</code></pre></div></div>
<p>And there we go, a call to <code class="high">_libsecinit_setup_app_sandbox</code> of <code class="high">libsystem_secinit.dylib</code> which means that our Sandbox has been created and we’re about to be placed into it as we start. The next few continue commands would finally fall into <code class="high">sandbox_check_common</code> of <code class="high">libsystem_sandbox.dylib</code> and then finally into <code class="high">LaunchServices</code> after which the app is started through <code class="high">AppKit`-[NSApplication init]</code>.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">(</span>lldb<span class="o">)</span> c
Process 13280 resuming
Process 13280 stopped
<span class="k">*</span> thread <span class="c">#1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1</span>
frame <span class="c">#0: 0x00007fff6a55f648 libsystem_kernel.dylib`__mac_syscall</span>
libsystem_kernel.dylib<span class="sb">`</span>__mac_syscall:
-> 0x7fff6a55f648 <+0>: movl <span class="nv">$0x200017d</span>, %eax <span class="p">;</span> imm <span class="o">=</span> 0x200017D
0x7fff6a55f64d <+5>: movq %rcx, %r10
0x7fff6a55f650 <+8>: syscall
0x7fff6a55f652 <+10>: jae 0x7fff6a55f65c <span class="p">;</span> <+20>
Target 0: <span class="o">(</span>iHex<span class="o">)</span> stopped.
<span class="o">(</span>lldb<span class="o">)</span> bt
<span class="k">*</span> thread <span class="c">#1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1</span>
<span class="k">*</span> frame <span class="c">#0: 0x00007fff6a55f648 libsystem_kernel.dylib`__mac_syscall</span>
frame <span class="c">#1: 0x00007fff6a731646 libsystem_sandbox.dylib`sandbox_check_common + 322</span>
frame <span class="c">#2: 0x00007fff6a7318f9 libsystem_sandbox.dylib`sandbox_check_by_audit_token + 177</span>
frame <span class="c">#3: 0x00007fff43ae952e LaunchServices`_LSIsAuditTokenSandboxed + 149</span>
frame <span class="c">#4: 0x00007fff6a3d5db8 libdispatch.dylib`_dispatch_client_callout + 8</span>
frame <span class="c">#5: 0x00007fff6a3d5d6b libdispatch.dylib`dispatch_once_f + 41</span>
frame <span class="c">#6: 0x00007fff439c7ed1 LaunchServices`_LSIsCurrentProcessSandboxed + 178</span>
frame <span class="c">#7: 0x00007fff43ae92ec LaunchServices`_LSCheckMachPortAccessForAuditToken + 72</span>
frame <span class="c">#8: 0x00007fff43ae9448 LaunchServices`_LSCheckLSDServiceAccessForAuditToken + 153</span>
frame <span class="c">#9: 0x00007fff439c097a LaunchServices`_LSRegisterSelf + 64</span>
frame <span class="c">#10: 0x00007fff439b9a7c LaunchServices`_LSApplicationCheckIn + 5420</span>
frame <span class="c">#11: 0x00007fff40d7192c HIServices`_RegisterApplication + 4617</span>
frame <span class="c">#12: 0x00007fff40d7064c HIServices`GetCurrentProcess + 24</span>
frame <span class="c">#13: 0x00007fff417cf4ab HIToolbox`MenuBarInstance::GetAggregateUIMode(unsigned int*, unsigned int*) + 63</span>
frame <span class="c">#14: 0x00007fff417cf435 HIToolbox`MenuBarInstance::IsVisible() + 51</span>
frame <span class="c">#15: 0x00007fff3fa71197 AppKit`_NSInitializeAppContext + 35</span>
frame <span class="c">#16: 0x00007fff3fa70590 AppKit`-[NSApplication init] + 443</span>
frame <span class="c">#17: 0x00007fff3fa701e6 AppKit`+[NSApplication sharedApplication] + 138</span>
frame <span class="c">#18: 0x00007fff3fa718b2 AppKit`NSApplicationMain + 356</span>
frame <span class="c">#19: 0x0000000100001c04 iHex`___lldb_unnamed_symbol1$$iHex + 52</span>
<span class="o">(</span>lldb<span class="o">)</span>
</code></pre></div></div>
<p>After this, the application interface is rapidly built by the rest of the components and the app starts sandboxed.</p>
<h3 id="acknowledgements">Acknowledgements</h3>
<p>Thank you a lot for reading through this! I hope you find it useful. In the end, I’d like to thank Jonathan Levin for both his presentation at HITBGSEC 2016 about the Sandbox and for his marvelous *OS Internals Volume III book which is pretty much the main resources I’ve studied to understand the sandbox and to be able to write this article. It’s Jonathan whom you shall thank for the research and the effort put into the uncovering of Apple Sandbox’ inner workings and if you can buy his *OS Internals series, please do - they are absolutely fantastic books with tons of research put into iOS, macOS, watchOS and tvOS.</p>
<h3 id="bibliography">Bibliography</h3>
<ul>
<li>2016 J. LEVIN, <i><a href="https://www.amazon.com/MacOS-iOS-Internals-III-Insecurity/dp/0991055535/ref=as_sl_pc_qf_sp_asin_til?tag=newosxbookcom-20&linkCode=w00&linkId=0b61c945365c9c37cd3cf88f10a5f629&creativeASIN=0991055535">*OS Internals Volume III Security & Insecurity</a></i>, NY, USA, TechnoloGeeks</li>
<li>2016 J. LEVIN, <i>The Apple Sandbox: Deeper Into The Quagmire</i>, presentation at HITBGSEC 2016 conference</li>
<li><a href="https://developer.apple.com/library/archive/documentation/Security/Conceptual/AppSandboxDesignGuide/AboutAppSandbox/AboutAppSandbox.html"><i>Apple Sandbox Design Guide</i></a>, accessed on December 27 2018</li>
<li><a href="https://developer.apple.com/library/archive/documentation/Security/Conceptual/AppSandboxDesignGuide/AppSandboxInDepth/AppSandboxInDepth.html"><i>App Sandbox In Depth</i></a>, accessed on December 27 2018</li>
<li>2016 D. Thiel, <i>iOS Application Security The Definitive Guide for Hackers and Developers</i>, No Starch Press, San Francisco, USA</li>
</ul>
<h3 id="contact-me">Contact me</h3>
<ul>
<li>Twitter: <a href="https://twitter.com/FCE365">GeoSn0w (@FCE365)</a></li>
<li>YouTube: <a href="https://youtube.com/fce365official">F.C.E. 365 TV- iDevice Central</a></li>
</ul>Hi there! It’s GeoSn0w. The macOS Sandbox has always been a mysterious thing that I liked to poke at with various tools and with the knowledge I have gathered from reference books such as Jonathan Levin’s *OS Internals, and Apple’s own not-so-detailed documentation. Of course, it’s nothing new that Apple’s documentation on their own security mechanisms isn’t the best. The Sandbox has a very long history and it’s been with us, macOS users for quite a long time, only to spin off to iOS and the rest of the *OSes and to become more powerful over time. Apple’s been doing their darn best to harden the Sandbox as well as many other security mechanisms in their operating systems, so let’s grab a cup of coffee and dive a bit into the marvel that is the macOS Sandbox.Debugging macOS Kernel For Fun2018-12-02T00:00:00+00:002018-12-02T00:00:00+00:00https://geosn0w.github.io/Debugging-macOS-Kernel-For-Fun<p>Hi there! It’s GeoSn0w. Debugging the damn kernel is a very entertaining thing to do (until you provoke a serious exception, that is, and the kernel crawls into a corner from which it refuses to get out). Unfortunately, it’s not an easy task nowadays and Apple seems to want to make it harder and harder. At first, by hiding under lock and key the documentation about the <code class="high">debug</code> boot arguments, and then by moving the Kernel Debug Kit under the Developer Account-only Downloads section. There are many write-ups on the internet about debugging the kernel on macOS but many of them are outdated as hell and the NVRAM boot arguments they tell you to set are no longer working. Some of them stop at just the “now you should have a working debug session” - so what? what do I do next? I wanna have fun Goddammit! In this write-up I am doing my best to provide the most accurate information for 2019, the right commands, the right <code class="high">boot-args</code> and of course, practical examples you can begin with.</p>
<h3 id="a-note-for-the-l33t-h4xxors">A note for the l33t h4xxors</h3>
<p>If you are going to say “well if people don’t know what to do with a kernel debugger they shouldn’t use one”, please segfault. You’ve been a beginner once and wanted to have fun and learn so shut up.</p>
<h3 id="getting-started-with-kernel-debugging-on-macos">Getting started with Kernel debugging on macOS</h3>
<p>Okay, so the first things we need to sort out is the lab. You need to have a device of which kernel you want to debug (in my case I am using my iMac 2011 as a debuggee) and a device from where you do the debugging (I am using my MacBook Pro 2009 for this). You can connect the two in various ways I will discuss in this write-up, but in my case, the best method (and the most reliable) seems to be via a Firewire cable between the two (that is because both my machines have actual firewire ports, not USB-C bullshit).</p>
<p>With the hardware part set up, we need some software. You CAN theoretically debug the <code class="high">RELEASE</code> kernel, but when you’re a beginner the <code class="high">Development</code> one is much better. By default, macOS comes with a <code class="high">RELEASE</code> fused kernel located in <code class="high">/System/Library/Kernels/kernel</code> where <code class="high">kernel</code> is a <code class="high">Mach-O 64-bit executable x86_64</code>. We can get ourselves the <code class="high">Development</code> kernel for our macOS version by navigating to Apple Developer portal and downloading the Kernel Debug Kit. It’s surprising that Apple only put the kit under a normal, free Apple Developer Account lock; I would have expected them to put it under the paid Apple Developer Account downloads by now.</p>
<p>Anyways, once you navigate to this <a href="https://developer.apple.com/downloads/index.action?q=Kernel%20Debug%20Kit">Apple Developer Portal Downloads</a> section, you will see something like this:</p>
<p align="center">
<img src="https://user-images.githubusercontent.com/15067741/49338190-7ba07380-f5ec-11e8-84bf-69e26c5715bf.png" />
</p>
<p><b>VERY IMPORTANT!</b> You should get the appropriate kernel debug kit for your specific macOS version! You will boot the downloaded kernel later and if it doesn’t match your macOS version, it will NOT boot! I am not responsible for any damages to your files, computer, life, cat, whatever. Proceed at your own risk.</p>
<h3 id="finding-the-proper-kernel-debug-kit-for-your-macos-version-">Finding the proper Kernel Debug Kit for your macOS version [!]</h3>
<p>In order to locate the proper Kernel Debug Kit, you must know your macOS version and the actual build number. You can easily see what macOS version you are running by going to the Apple logo, pressing “About This Mac”, and reading the version in the window that appears, for example, “Version 10.13.6”.</p>
<p>For the actual build number, you can either click once on the “Version” label in that “About This Mac” window, or you can run the terminal command <code class="high">sw_vers | grep BuildVersion</code>. In my case running the command outputs “BuildVersion: 17G65”.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Last login: Sun Dec 2 03:58:16 on ttys000
Isabella:~ geosn0w<span class="nv">$ </span>sw_vers | <span class="nb">grep </span>BuildVersion
BuildVersion: 17G65
Isabella:~ geosn0w<span class="nv">$ </span>
</code></pre></div></div>
<p>So, in my case, I am running macOS High Sierra (10.13.6) build number 17G65. Looking in the Downloads section I could immediately find my version listed so I can download the .DMG file containing the installation files. The download is pretty small.</p>
<p align="center">
<img src="https://user-images.githubusercontent.com/15067741/49338318-93c4c280-f5ed-11e8-84ef-5313af537f9a.png" />
</p>
<h3 id="preparing-the-debuggee-for-being-debugged-by-the-debugger-">Preparing the debuggee for being debugged by the debugger ;)</h3>
<p>With the Debug Kit downloaded on the debuggee (that is the machine whose kernel you wanna debug), mount the DMG file by double-clicking on it. Inside the DMG you will find a file called <code class="high">KernelDebugKit.pkg</code>. Double-click that and follow the installation wizard. It will ask you for your macOS login password. If asked, do not move the installer to trash. You will need it later.</p>
<p>When the installation is complete it will look something like this.</p>
<p align="center">
<img src="https://user-images.githubusercontent.com/15067741/49338411-c02d0e80-f5ee-11e8-863d-2c7cda6acf93.png" />
</p>
<p>After the installation completes, navigate to <code class="high">/Library/Developer/KDKs</code>. There you will have a folder named <code class="high">KDK_YOUR_VERSION_BUILDNUMBER.kdk</code>. In my case the folder is called <code class="high">KDK_10.13.6_17G65.kdk</code>. Open the folder and inside it you will find another folder called “System”. Navigate into the folder, then into “Library” and then into “Kernels”. In that folder you will find a few kernel binaries, some Xcode Debug Symbol files (.dSYM), etc. You are interested in the file called <code class="high">kernel.development</code>.</p>
<p>Copy the <code class="high">kernel.development</code> and paste into <code class="high">/System/Library/Kernels/</code> alongside your release kernel binary. When you are done, you should have two kernels on your macOS installation, a <code class="high">RELEASE</code> one and a <code class="high">DEVELOPMENT</code> one.</p>
<h3 id="disabling-sip-on-the-debuggee">Disabling SIP on the debuggee</h3>
<p>For proper debugging, you may need to disable <code class="high">SIP (System Integrity Protection)</code> on the machine whose kernel you wanna debug. To do that, reboot the machine in <code class="high">Recovery Mode</code>. To do that, reboot the machine and when you hear the “BOONG!”, or when the screen turns on, press <code class="high">CMD + R</code>. Wait a few seconds for it to boot into Recovery Mode user interface, and open “Terminal” from the top bar.</p>
<p>In the Recovery Terminal, write <code class="high">csrutil disable</code>. Then reboot the machine and boot it normally to macOS.</p>
<h3 id="setting-the-correct-nvram-boot-args-as-of-20182019">Setting the correct NVRAM boot-args as of 2018/2019</h3>
<p>The <code class="high">boot-args</code> have been changed during the years by Apple so what you find on the internet may or may not work depending on how old the write-up is. The following <code class="high">boot-args</code> have been tested and are working with macOS High Sierra as of 2018.</p>
<p><b>NOTE!</b> The following <code class="high">boot-args</code> assume you are doing this over Firewire or via Firewire through Thunderbolt adpter.</p>
<p><b>If you are using a FireWire cable through a real FireWire port (older Macs):</b></p>
<p>In the Terminal run the following command:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>nvram boot-args<span class="o">=</span><span class="s2">"debug=0x8146 kdp_match_name=firewire fwdebug=0x40 pmuflags=1 -v"</span>
</code></pre></div></div>
<p><b>If you are using a FireWire through ThunderBolt adapter:</b></p>
<p>In the Terminal run the following command:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>nvram boot-args<span class="o">=</span><span class="s2">"debug=0x8146 kdp_match_name=firewire fwkdp=0x8000 fwdebug=0x40 pmuflags=1 -v"</span>
</code></pre></div></div>
<p>The difference is that <code class="high">fwkdp=0x8000</code> tells <code class="high">IOFireWireFamily.kext::AppleFWOHCI_KDP</code> to use the non-built-in firewire <-> thunderbolt adapter for the debugging session.</p>
<p>This is pretty much it, the debuggee is ready to be debugged after a reboot, but let me explain you a bit what the boot arguments do.</p>
<ul>
<li><code class="high">debug=0x8146</code> -> This enables the debugging and allows us to press the Power button to trigger a <code class="high">NMI</code> This stands for <code class="high">Non-Maskable Interrupt</code> and it is used to allow the debugger to connect.</li>
<li><code class="high">kdp_match_name=firewire</code> -> This allows us to debug via <code class="high">FireWireKDP</code>.</li>
<li><code class="high">fwkdp=0x8000</code> -> As I explained earlier, this tells the kext to use the thunderbolt to firewire adapter. Don't set it if you use normal Firewire ports.</li>
<li><code class="high">fwdebug=0x40</code> -> Enables more verbose output from the <code class="high">AppleFWOHCI_KDP</code> driver, it is useful for troubleshooting.</li>
<li><code class="high">pmuflags=1</code> -> This one disables the <code class="high">Watchdog timer</code>.</li>
<li><code class="high">-v</code> -> The simplest of birds. This one tells the computer to boot verbose instead of the normal Apple logo and progress bar. This is extremely useful for troubleshooting, not only when you debug but also when you have boot loops.</li>
</ul>
<p>Aside from these boot arguments that we set, macOS supports more args that are defined in <a href="http://newosxbook.com/src.jl?tree=xnu&file=/osfmk/kern/debug.h"><code class="high">/osfmk/kern/debug.h</code></a> which I am going to list below. These were taken from <code class="high">xnu-4570.41.2</code>.</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">...</span>
<span class="cm">/* Debug boot-args */</span>
<span class="cp">#define DB_HALT 0x1
</span><span class="c1">//#define DB_PRT 0x2 -- obsolete</span>
<span class="cp">#define DB_NMI 0x4
#define DB_KPRT 0x8
#define DB_KDB 0x10
#define DB_ARP 0x40
#define DB_KDP_BP_DIS 0x80
</span><span class="c1">//#define DB_LOG_PI_SCRN 0x100 -- obsolete</span>
<span class="cp">#define DB_KDP_GETC_ENA 0x200
</span>
<span class="cp">#define DB_KERN_DUMP_ON_PANIC 0x400 </span><span class="cm">/* Trigger core dump on panic*/</span><span class="cp">
#define DB_KERN_DUMP_ON_NMI 0x800 </span><span class="cm">/* Trigger core dump on NMI */</span><span class="cp">
#define DB_DBG_POST_CORE 0x1000 </span><span class="cm">/*Wait in debugger after NMI core */</span><span class="cp">
#define DB_PANICLOG_DUMP 0x2000 </span><span class="cm">/* Send paniclog on panic,not core*/</span><span class="cp">
#define DB_REBOOT_POST_CORE 0x4000 </span><span class="cm">/* Attempt to reboot after
* post-panic crashdump/paniclog
* dump.
*/</span><span class="cp">
#define DB_NMI_BTN_ENA 0x8000 </span><span class="cm">/* Enable button to directly trigger NMI */</span><span class="cp">
#define DB_PRT_KDEBUG 0x10000 </span><span class="cm">/* kprintf KDEBUG traces */</span><span class="cp">
#define DB_DISABLE_LOCAL_CORE 0x20000 </span><span class="cm">/* ignore local kernel core dump support */</span><span class="cp">
#define DB_DISABLE_GZIP_CORE 0x40000 </span><span class="cm">/* don't gzip kernel core dumps */</span><span class="cp">
#define DB_DISABLE_CROSS_PANIC 0x80000 </span><span class="cm">/* x86 only - don't trigger cross panics. Only
* necessary to enable x86 kernel debugging on
* configs with a dev-fused co-processor running
* release bridgeOS.
*/</span><span class="cp">
#define DB_REBOOT_ALWAYS 0x100000 </span><span class="cm">/* Don't wait for debugger connection */</span><span class="cp">
</span><span class="p">...</span>
</code></pre></div></div>
<h3 id="preparing-the-debugger-machine">Preparing the debugger machine</h3>
<p>Okay, now that the debuggee is ready, we need to configure the machine where the debugger will run. For that, I am using another macOS machine running El Capitan, but that matters less. Remember that Kernel Debug Kit we installed on the debuggee? We need to install it on the debugger machine too. The difference is that we will NOT move the kernels and we will not set any boot arguments on the debugger. We need the kernel because we are going to use <code class="high">lldb</code> to perform the debugging. If you’re familiar with GDB instead, don’t worry. There is a <a href="https://lldb.llvm.org/lldb-gdb.html"> GDB -> LLDB command sheet available right here</a>.</p>
<p>Note: You should install the same macOS Kernel Debug toolkit on the debugger even if it doesn’t run the same macOS version as the debuggee because we will not boot any kernel on the debugger.</p>
<p>After you installed the toolkit, it’s time to connect.</p>
<h3 id="debugging-the-kernel">Debugging the kernel</h3>
<p>To begin, reboot the debuggee. You will see that it boots into a text-mode console which spits out verbose boot information. Wait until you see “DSMOS has arrived!” on the screen and press the Power button once. Don’t hold it pressed. On the debuggee, you will see that it is waiting for a debugger to be connected.</p>
<p><b>On the debugger machine:</b></p>
<p>Open a Terminal window and start <code class="high">fwkdp -v</code>, this is the <code class="high">FireWire KDP Tool</code> and will listen to the FireWire interface and redirect the data to the <code class="high">localhost</code> so that you can set the KDP target as <code class="high">localhost</code> or <code class="high">127.0.0.1</code>. You should get an output similar to this:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>MacBook-Pro-van-Mac:~ mac<span class="nv">$ </span>fwkdp <span class="nt">-v</span>
FireWire KDP Tool <span class="o">(</span>v1.6<span class="o">)</span>
Matched on device 0x00002403
Created plugin interface 0x7f9e50c03548 with result 0x00000000
Created device interface 0x7f9e50c0d508 with result 0x00000000
Opened device interface 0x7f9e50c0d508 with result 0x00000000
Added callback dispatcher with result 0x00000000
Created pseudo address space 0x7f9e50c0d778 at 0xf0430000
Address space enabled.
2018-12-02 05:51:05.453 fwkdp[5663:60796] CFSocketSetAddress listen failure: 102
Created KDP socket listener 0x7f9e50c0d940 with result 0
KDP Proxy and CoreDump-Receive dual mode active.
Use <span class="s1">'localhost'</span> as the KDP target <span class="k">in </span>gdb.
Ready.
</code></pre></div></div>
<p>Now, WITHOUT closing this window open another Terminal window and start <code class="high">lldb debugger</code> by passing it the kernel.development file you installed on the debugger machine as part of the Kernel Debug Kit. Remember, the kernel can be found at <code class="high">/Library/Developer/KDKs/</code>. There you will have a folder named <code class="high">KDK_YOUR_VERSION_BUILDNUMBER.kdk</code>. In my case the folder is called <code class="high">KDK_10.13.6_17G65.kdk</code>. and my full kernel path that I need is <code class="high">/Library/Developer/KDKs/KDK_10.13.6_17G65.kdk/System/Library/Kernels/kernel.development</code>.</p>
<p>The command in the new terminal window in MY case will be <code class="high">xcrun lldb /Library/Developer/KDKs/KDK_10.13.6_17G65.kdk/System/Library/Kernels/kernel.development</code></p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Last login: Sun Dec 2 10:37:51 on ttys000
MacBook-Pro-van-Mac:~ mac<span class="nv">$ </span>xcrun lldb /Library/Developer/KDKs/KDK_10.13.6_17G65.kdk/System/Library/Kernels/kernel.development
<span class="o">(</span>lldb<span class="o">)</span> target create <span class="s2">"/Library/Developer/KDKs/KDK_10.13.6_17G65.kdk/System/Library/Kernels/kernel.development"</span>
warning: <span class="s1">'kernel'</span> contains a debug script. To run this script <span class="k">in </span>this debug session:
<span class="nb">command </span>script import <span class="s2">"/Library/Developer/KDKs/KDK_10.13.6_17G65.kdk/System/Library/Kernels/kernel.development.dSYM/Contents/Resources/DWARF/../Python/kernel.py"</span>
To run all discovered debug scripts <span class="k">in </span>this session:
settings <span class="nb">set </span>target.load-script-from-symbol-file <span class="nb">true
</span>Current executable <span class="nb">set </span>to <span class="s1">'/Library/Developer/KDKs/KDK_10.13.6_17G65.kdk/System/Library/Kernels/kernel.development'</span> <span class="o">(</span>x86_64<span class="o">)</span><span class="nb">.</span>
</code></pre></div></div>
<p>As you can see, <code class="high">lldb</code> says that the “kernel” contains a debug script. In the lldb window that is now open, run <code class="high">settings set target.load-script-from-symbol-file true</code> to run the script.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Last login: Sun Dec 2 10:37:51 on ttys000
MacBook-Pro-van-Mac:~ mac<span class="nv">$ </span>xcrun lldb /Library/Developer/KDKs/KDK_10.13.6_17G65.kdk/System/Library/Kernels/kernel.development
<span class="o">(</span>lldb<span class="o">)</span> target create <span class="s2">"/Library/Developer/KDKs/KDK_10.13.6_17G65.kdk/System/Library/Kernels/kernel.development"</span>
warning: <span class="s1">'kernel'</span> contains a debug script. To run this script <span class="k">in </span>this debug session:
<span class="nb">command </span>script import <span class="s2">"/Library/Developer/KDKs/KDK_10.13.6_17G65.kdk/System/Library/Kernels/kernel.development.dSYM/Contents/Resources/DWARF/../Python/kernel.py"</span>
To run all discovered debug scripts <span class="k">in </span>this session:
settings <span class="nb">set </span>target.load-script-from-symbol-file <span class="nb">true
</span>Current executable <span class="nb">set </span>to <span class="s1">'/Library/Developer/KDKs/KDK_10.13.6_17G65.kdk/System/Library/Kernels/kernel.development'</span> <span class="o">(</span>x86_64<span class="o">)</span><span class="nb">.</span>
<span class="o">(</span>lldb<span class="o">)</span> settings <span class="nb">set </span>target.load-script-from-symbol-file <span class="nb">true
</span>Loading kernel debugging from /Library/Developer/KDKs/KDK_10.13.6_17G65.kdk/System/Library/Kernels/kernel.development.dSYM/Contents/Resources/DWARF/../Python/kernel.py
LLDB version lldb-360.1.70
settings <span class="nb">set </span>target.process.python-os-plugin-path <span class="s2">"/Library/Developer/KDKs/KDK_10.13.6_17G65.kdk/System/Library/Kernels/kernel.development.dSYM/Contents/Resources/DWARF/../Python/lldbmacros/core/operating_system.py"</span>
settings <span class="nb">set </span>target.trap-handler-names hndl_allintrs hndl_alltraps trap_from_kernel hndl_double_fault hndl_machine_check _fleh_prefabt _ExceptionVectorsBase _ExceptionVectorsTable _fleh_undef _fleh_dataabt _fleh_irq _fleh_decirq _fleh_fiq_generic _fleh_dec
<span class="nb">command </span>script import <span class="s2">"/Library/Developer/KDKs/KDK_10.13.6_17G65.kdk/System/Library/Kernels/kernel.development.dSYM/Contents/Resources/DWARF/../Python/lldbmacros/xnu.py"</span>
xnu debug macros loaded successfully. Run showlldbtypesummaries to <span class="nb">enable type </span>summaries.
settings <span class="nb">set </span>target.process.optimization-warnings <span class="nb">false</span>
<span class="o">(</span>lldb<span class="o">)</span>
</code></pre></div></div>
<p>Now we can finally connect <code class="high">lldb</code> to the live kernel by writing <code class="high">kdp-remote localhost</code>. If you did everything right, the kernel should connect and you should have an output like this. A LOT of text will start to pour into your lldb window initially, then it should come to a rest state.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">(</span>lldb<span class="o">)</span> kdp-remote localhost
Version: Darwin Kernel Version 17.7.0: Wed Oct 10 23:06:14 PDT 2018<span class="p">;</span> root:xnu-4570.71.13~1/DEVELOPMENT_X86_64<span class="p">;</span> <span class="nv">UUID</span><span class="o">=</span>1718D865-98B4-3F6E-97CF-42BF0D02ADD7<span class="p">;</span> <span class="nv">stext</span><span class="o">=</span>0xffffff802e800000
Kernel UUID: 1718D865-98B4-3F6E-97CF-42BF0D02ADD7
Load Address: 0xffffff802e800000
Kernel slid 0x2e600000 <span class="k">in </span>memory.
Loaded kernel file /Library/Developer/KDKs/KDK_10.13.6_17G3025.kdk/System/Library/Kernels/kernel.development
Loading 152 kext modules warning: Can<span class="s1">'t find binary/dSYM for com.apple.kec.Libm (BC3F7DA4-03EA-30F7-B44A-62C249D51C10)
.warning: Can'</span>t find binary/dSYM <span class="k">for </span>com.apple.kec.corecrypto <span class="o">(</span>B081B8C1-1DFF-342F-8DF2-C3AA925ECA3A<span class="o">)</span>
.warning: Can<span class="s1">'t find binary/dSYM for com.apple.kec.pthread (E64F7A49-CBF0-3251-9F02-3655E3B3DD31)
.warning: Can'</span>t find binary/dSYM <span class="k">for </span>com.apple.iokit.IOACPIFamily <span class="o">(</span>95DA39BB-7C39-3742-A2E5-86C555E21D67<span class="o">)</span>
<span class="o">[</span>...]
.Target <span class="nb">arch</span>: x86_64
.. <span class="k">done</span><span class="nb">.</span>
Target <span class="nb">arch</span>: x86_64
Instantiating threads completely from saved state <span class="k">in </span>memory.
Process 1 stopped
<span class="k">*</span> thread <span class="c">#2: tid = 0x0066, 0xffffff802e97a8d3 kernel.development`DebuggerWithContext [inlined] current_cpu_datap at cpu_data.h:401, name = '0xffffff80486a2338', queue = '0x0', stop reason = signal SIGSTOP</span>
frame <span class="c">#0: 0xffffff802e97a8d3 kernel.development`DebuggerWithContext [inlined] current_cpu_datap at cpu_data.h:401 [opt]</span>
</code></pre></div></div>
<p>Now we are connected to the live kernel. You can see that the process is stopped, this means that the kernel is frozen, this is why the boot stopped right where you left it, but now that the debugger has been attached, we can safely continue the boot process into the normal macOS desktop. To do that we just have to unfreeze (continue) the process. To do that, type “c” for continue and press enter until the boot continues (more text is poured on the debuggee screen)</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">(</span>lldb<span class="o">)</span> c
Process 1 resuming
Process 1 stopped
<span class="k">*</span> thread <span class="c">#2: tid = 0x0066, 0xffffff802e97a8d3 kernel.development`DebuggerWithContext [inlined] current_cpu_datap at cpu_data.h:401, name = '0xffffff80486a2338', queue = '0x0', stop reason = EXC_BREAKPOINT (code=3, subcode=0x0)</span>
frame <span class="c">#0: 0xffffff802e97a8d3 kernel.development`DebuggerWithContext [inlined] current_cpu_datap at cpu_data.h:401 [opt]</span>
<span class="o">(</span>lldb<span class="o">)</span> c
</code></pre></div></div>
<p>Once the debuggee has fully booted into the macOS and you are on your desktop, you can pretty much do whatever debugging you want. To run a debugger command you will have to trigger again a <code class="high">NMI</code>, to do that you press the Power button once. The debuggee screen will freeze but your debugger’s lldb screen will be active and you can read/write registers, read/write memory, disassemble at address, disassemble functions, etc. on the live kernel. To unfreeze it back you type again “c” and press enter on the lldb screen.</p>
<h3 id="practical-examples-of-kernel-debugging">Practical examples of Kernel debugging</h3>
<p><b>Example 1: Reading all the registers with lldb and writing “AAAAAAAA” to one of them</b></p>
<p>Okay, to read all the registers, trigger a <code class="high">NMI</code> by pressing the Power button and in the open lldb window type register <code class="high">read --all</code></p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">(</span>lldb<span class="o">)</span> register <span class="nb">read</span> <span class="nt">--all</span>
General Purpose Registers:
rax <span class="o">=</span> 0xffffff802f40ba40 kernel.development<span class="sb">`</span>processor_master
rbx <span class="o">=</span> 0x0000000000000000
rcx <span class="o">=</span> 0xffffff802f40ba40 kernel.development<span class="sb">`</span>processor_master
rdx <span class="o">=</span> 0x0000000000000000
rdi <span class="o">=</span> 0x0000000000000004
rsi <span class="o">=</span> 0xffffff7fb1483ff4
rbp <span class="o">=</span> 0xffffff817e8ccd50
rsp <span class="o">=</span> 0xffffff817e8ccd10
r8 <span class="o">=</span> 0x0000000000000000
r9 <span class="o">=</span> 0x0000000000000001
r10 <span class="o">=</span> 0x00000000000004d1
r11 <span class="o">=</span> 0x00000000000004d0
r12 <span class="o">=</span> 0x0000000000000000
r13 <span class="o">=</span> 0x0000000000000000
r14 <span class="o">=</span> 0x0000000000000000
r15 <span class="o">=</span> 0xffffff7fb1483ff4
rip <span class="o">=</span> 0xffffff802e97a8d3 kernel.development<span class="sb">`</span>DebuggerWithContext + 403 <span class="o">[</span>inlined] current_cpu_datap at cpu.c:220
kernel.development<span class="sb">`</span>DebuggerWithContext + 403 <span class="o">[</span>inlined] current_processor at debug.c:463
kernel.development<span class="sb">`</span>DebuggerWithContext + 403 <span class="o">[</span>inlined] DebuggerTrapWithState + 46 at debug.c:537
kernel.development<span class="sb">`</span>DebuggerWithContext + 357 at debug.c:537
rflags <span class="o">=</span> 0x0000000000000046
cs <span class="o">=</span> 0x0000000000000008
fs <span class="o">=</span> 0x0000000000000000
gs <span class="o">=</span> 0x0000000000000000
Floating Point Registers:
fcw <span class="o">=</span> 0x0000
fsw <span class="o">=</span> 0x0000
ftw <span class="o">=</span> 0x00
fop <span class="o">=</span> 0x0000
ip <span class="o">=</span> 0x00000000
cs <span class="o">=</span> 0x0000
dp <span class="o">=</span> 0x00000000
ds <span class="o">=</span> 0x0000
mxcsr <span class="o">=</span> 0x00000000
mxcsrmask <span class="o">=</span> 0x00000000
stmm0 <span class="o">=</span> <span class="o">{</span>0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00<span class="o">}</span>
stmm1 <span class="o">=</span> <span class="o">{</span>0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00<span class="o">}</span>
stmm2 <span class="o">=</span> <span class="o">{</span>0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00<span class="o">}</span>
stmm3 <span class="o">=</span> <span class="o">{</span>0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00<span class="o">}</span>
stmm4 <span class="o">=</span> <span class="o">{</span>0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00<span class="o">}</span>
stmm5 <span class="o">=</span> <span class="o">{</span>0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00<span class="o">}</span>
stmm6 <span class="o">=</span> <span class="o">{</span>0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00<span class="o">}</span>
stmm7 <span class="o">=</span> <span class="o">{</span>0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00<span class="o">}</span>
xmm0 <span class="o">=</span> <span class="o">{</span>0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00<span class="o">}</span>
xmm1 <span class="o">=</span> <span class="o">{</span>0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00<span class="o">}</span>
xmm2 <span class="o">=</span> <span class="o">{</span>0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00<span class="o">}</span>
xmm3 <span class="o">=</span> <span class="o">{</span>0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00<span class="o">}</span>
xmm4 <span class="o">=</span> <span class="o">{</span>0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00<span class="o">}</span>
xmm5 <span class="o">=</span> <span class="o">{</span>0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00<span class="o">}</span>
xmm6 <span class="o">=</span> <span class="o">{</span>0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00<span class="o">}</span>
xmm7 <span class="o">=</span> <span class="o">{</span>0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00<span class="o">}</span>
xmm8 <span class="o">=</span> <span class="o">{</span>0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00<span class="o">}</span>
xmm9 <span class="o">=</span> <span class="o">{</span>0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00<span class="o">}</span>
xmm10 <span class="o">=</span> <span class="o">{</span>0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00<span class="o">}</span>
xmm11 <span class="o">=</span> <span class="o">{</span>0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00<span class="o">}</span>
xmm12 <span class="o">=</span> <span class="o">{</span>0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00<span class="o">}</span>
xmm13 <span class="o">=</span> <span class="o">{</span>0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00<span class="o">}</span>
xmm14 <span class="o">=</span> <span class="o">{</span>0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00<span class="o">}</span>
xmm15 <span class="o">=</span> <span class="o">{</span>0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00<span class="o">}</span>
Exception State Registers:
3 registers were unavailable.
<span class="o">(</span>lldb<span class="o">)</span>
</code></pre></div></div>
<p>Now let’s write to one of the registers. DO NOT write to a register that is not set to <code class="high">0x0000000000000000</code> because you will overwrite something. Find one that is empty. In my case, <code class="high">R13</code> is empty (<code class="high">r13 = 0x0000000000000000</code>) so I can write garbage to it to prove my point. To write a string of AAAs to the register I can replace it’s value to <code class="high">0x4141414141414141</code> where <code class="high">0x41</code> is the hex representation for ASCII character “A”. To overwrite the register I can use the command <code class="high">register write r13 0x4141414141414141</code>. Sure enough, if we read the registers again the change is in place:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">(</span>lldb<span class="o">)</span> register write R13 0x4141414141414141
<span class="o">(</span>lldb<span class="o">)</span> register <span class="nb">read</span> <span class="nt">--all</span>
General Purpose Registers:
rax <span class="o">=</span> 0xffffff802f40ba40 kernel.development<span class="sb">`</span>processor_master
rbx <span class="o">=</span> 0x0000000000000000
rcx <span class="o">=</span> 0xffffff802f40ba40 kernel.development<span class="sb">`</span>processor_master
rdx <span class="o">=</span> 0x0000000000000000
rdi <span class="o">=</span> 0x0000000000000004
rsi <span class="o">=</span> 0xffffff7fb1483ff4
rbp <span class="o">=</span> 0xffffff817e8ccd50
rsp <span class="o">=</span> 0xffffff817e8ccd10
r8 <span class="o">=</span> 0x0000000000000000
r9 <span class="o">=</span> 0x0000000000000001
r10 <span class="o">=</span> 0x00000000000004d1
r11 <span class="o">=</span> 0x00000000000004d0
r12 <span class="o">=</span> 0x0000000000000000
r13 <span class="o">=</span> 0x4141414141414141 <<span class="nt">--</span> Yee overwritten this.
r14 <span class="o">=</span> 0x0000000000000000
r15 <span class="o">=</span> 0xffffff7fb1483ff4
rip <span class="o">=</span> 0xffffff802e97a8d3 kernel.development<span class="sb">`</span>DebuggerWithContext + 403 <span class="o">[</span>inlined] current_cpu_datap at cpu.c:220
kernel.development<span class="sb">`</span>DebuggerWithContext + 403 <span class="o">[</span>inlined] current_processor at debug.c:463
kernel.development<span class="sb">`</span>DebuggerWithContext + 403 <span class="o">[</span>inlined] DebuggerTrapWithState + 46 at debug.c:537
kernel.development<span class="sb">`</span>DebuggerWithContext + 357 at debug.c:537
rflags <span class="o">=</span> 0x0000000000000046
cs <span class="o">=</span> 0x0000000000000008
fs <span class="o">=</span> 0x0000000000000000
gs <span class="o">=</span> 0x0000000000000000
Floating Point Registers:
fcw <span class="o">=</span> 0x0000
fsw <span class="o">=</span> 0x0000
ftw <span class="o">=</span> 0x00
fop <span class="o">=</span> 0x0000
ip <span class="o">=</span> 0x00000000
cs <span class="o">=</span> 0x0000
dp <span class="o">=</span> 0x00000000
ds <span class="o">=</span> 0x0000
mxcsr <span class="o">=</span> 0x00000000
mxcsrmask <span class="o">=</span> 0x00000000
stmm0 <span class="o">=</span> <span class="o">{</span>0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00<span class="o">}</span>
stmm1 <span class="o">=</span> <span class="o">{</span>0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00<span class="o">}</span>
stmm2 <span class="o">=</span> <span class="o">{</span>0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00<span class="o">}</span>
stmm3 <span class="o">=</span> <span class="o">{</span>0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00<span class="o">}</span>
stmm4 <span class="o">=</span> <span class="o">{</span>0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00<span class="o">}</span>
stmm5 <span class="o">=</span> <span class="o">{</span>0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00<span class="o">}</span>
stmm6 <span class="o">=</span> <span class="o">{</span>0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00<span class="o">}</span>
stmm7 <span class="o">=</span> <span class="o">{</span>0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00<span class="o">}</span>
xmm0 <span class="o">=</span> <span class="o">{</span>0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00<span class="o">}</span>
xmm1 <span class="o">=</span> <span class="o">{</span>0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00<span class="o">}</span>
xmm2 <span class="o">=</span> <span class="o">{</span>0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00<span class="o">}</span>
xmm3 <span class="o">=</span> <span class="o">{</span>0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00<span class="o">}</span>
xmm4 <span class="o">=</span> <span class="o">{</span>0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00<span class="o">}</span>
xmm5 <span class="o">=</span> <span class="o">{</span>0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00<span class="o">}</span>
xmm6 <span class="o">=</span> <span class="o">{</span>0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00<span class="o">}</span>
xmm7 <span class="o">=</span> <span class="o">{</span>0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00<span class="o">}</span>
xmm8 <span class="o">=</span> <span class="o">{</span>0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00<span class="o">}</span>
xmm9 <span class="o">=</span> <span class="o">{</span>0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00<span class="o">}</span>
xmm10 <span class="o">=</span> <span class="o">{</span>0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00<span class="o">}</span>
xmm11 <span class="o">=</span> <span class="o">{</span>0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00<span class="o">}</span>
xmm12 <span class="o">=</span> <span class="o">{</span>0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00<span class="o">}</span>
xmm13 <span class="o">=</span> <span class="o">{</span>0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00<span class="o">}</span>
xmm14 <span class="o">=</span> <span class="o">{</span>0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00<span class="o">}</span>
xmm15 <span class="o">=</span> <span class="o">{</span>0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00<span class="o">}</span>
Exception State Registers:
3 registers were unavailable.
<span class="o">(</span>lldb<span class="o">)</span>
</code></pre></div></div>
<p><b>NOTE:</b> Of course, when you wanna read a single register you don’t have to run <code class="high">register read --all</code>, you can simply specify the register with <code class="high">register read [register]</code> for example <code class="high">register read r13</code>.</p>
<p><b>Example 2: Changing the Kernel version and name when running <code class="high">uname -a</code></b></p>
<p>Time to do some real memory R/W to the kernel because we can. As you probably know, the command <code class="high">uname -a</code> in the Terminal lists the name of the kernel, the version, the, and the build date. What if we change that to whatever we want?</p>
<p>At first, we have no idea where the kernel stores that information so we need to find that. To do that we can use any Disassembler like IDA Pro, Hopper Disassembler, Jtool, Binary Ninja, etc.</p>
<p>I will use IDA Pro for this task. What we’re going to do is to load the kernel. development file into IDA Pro and let IDA analyze it. The analysis may take a while so please be patient. The Kernel ain’t small. When IDA finishes, the output should look like this, more or less. You will know when IDA finished because it will say “AU: idle” in the left bottom corner.</p>
<p align="center">
<img src="https://user-images.githubusercontent.com/15067741/49339255-3afd2600-f5fd-11e8-9104-231c46548fa3.png" />
</p>
<p>Now, we have to find that string. We know that the kernel name is <code class="high">Darwin</code> when the uname -a command is executed in Terminal so in order to look for it in IDA, we go to the top bar -> View -> Open subviews -> Strings.
A new Strings window will appear and if you press <code class="high">CTRL + F</code> inside it a search box will appear at the bottom where we can search for Darwin. And what do you know? The whole string is there.</p>
<p align="center">
<img src="https://user-images.githubusercontent.com/15067741/49339322-e312ef00-f5fd-11e8-957a-46965a3e288a.png" />
</p>
<p>Double-click that and you will be redirected to a constant called <code class="high">_version</code>. So now we know. The constant is called “version” and that is what we have to look for. You may be inclined to copy the address of the constant from the IDA disassembly but WRONG! The Kernel uses <code class="high">KASLR</code> or <code class="high">Kernel Address Space Layout Randomization</code> so the address will not be the same, it will be slid. But you don’t need to know the address anyways, you can get it easily with lldb on the debugger machine.</p>
<p align="center">
<img src="https://user-images.githubusercontent.com/15067741/49339365-8e23a880-f5fe-11e8-9633-b35da9c79498.png" />
</p>
<p><b>Let’s get the address of the “version” constant.</b></p>
<p>It’s actually very simple. Trigger a <code class="high">NMI</code> by pressing the Power Button (if you continued the process) and write <code class="high">print &(version)</code>.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">(</span>lldb<span class="o">)</span> print &<span class="o">(</span>version<span class="o">)</span>
<span class="o">(</span>const char <span class="o">(</span><span class="k">*</span><span class="o">)[</span>101]<span class="o">)</span> <span class="nv">$8</span> <span class="o">=</span> 0xffffff802f0f68f0
<span class="o">(</span>lldb<span class="o">)</span>
</code></pre></div></div>
<p>AHAM! So in my case the <code class="high">const char version</code> is at address <code class="high">0xffffff802f0f68f0</code>. Sure enough, if we list the character array it shows like this:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">(</span>lldb<span class="o">)</span> print version
<span class="o">(</span>const char <span class="o">[</span>101]<span class="o">)</span> <span class="nv">$9</span> <span class="o">=</span> <span class="o">{</span>
<span class="o">[</span>0] <span class="o">=</span> <span class="s1">'D'</span>
<span class="o">[</span>1] <span class="o">=</span> <span class="s1">'a'</span>
<span class="o">[</span>2] <span class="o">=</span> <span class="s1">'r'</span>
<span class="o">[</span>3] <span class="o">=</span> <span class="s1">'w'</span>
<span class="o">[</span>4] <span class="o">=</span> <span class="s1">'i'</span>
<span class="o">[</span>5] <span class="o">=</span> <span class="s1">'n'</span>
<span class="o">[</span>6] <span class="o">=</span> <span class="s1">' '</span>
<span class="o">[</span>7] <span class="o">=</span> <span class="s1">'K'</span>
<span class="o">[</span>8] <span class="o">=</span> <span class="s1">'e'</span>
<span class="o">[</span>9] <span class="o">=</span> <span class="s1">'r'</span>
<span class="o">[</span>10] <span class="o">=</span> <span class="s1">'n'</span>
<span class="o">[</span>11] <span class="o">=</span> <span class="s1">'e'</span>
<span class="o">[</span>12] <span class="o">=</span> <span class="s1">'l'</span>
<span class="o">[</span>13] <span class="o">=</span> <span class="s1">' '</span>
<span class="o">[</span>14] <span class="o">=</span> <span class="s1">'V'</span>
<span class="o">[</span>15] <span class="o">=</span> <span class="s1">'e'</span>
<span class="o">[</span>16] <span class="o">=</span> <span class="s1">'r'</span>
<span class="o">[</span>17] <span class="o">=</span> <span class="s1">'s'</span>
<span class="o">[</span>18] <span class="o">=</span> <span class="s1">'i'</span>
<span class="o">[</span>19] <span class="o">=</span> <span class="s1">'o'</span>
<span class="o">[</span>20] <span class="o">=</span> <span class="s1">'n'</span>
<span class="o">[</span>21] <span class="o">=</span> <span class="s1">' '</span>
<span class="o">[</span>22] <span class="o">=</span> <span class="s1">'1'</span>
<span class="o">[</span>23] <span class="o">=</span> <span class="s1">'7'</span>
<span class="o">[</span>24] <span class="o">=</span> <span class="s1">'.'</span>
<span class="o">[</span>25] <span class="o">=</span> <span class="s1">'7'</span>
<span class="o">[</span>26] <span class="o">=</span> <span class="s1">'.'</span>
<span class="o">[</span>27] <span class="o">=</span> <span class="s1">'0'</span>
<span class="o">[</span>28] <span class="o">=</span> <span class="s1">':'</span>
<span class="o">[</span>29] <span class="o">=</span> <span class="s1">' '</span>
<span class="o">[</span>30] <span class="o">=</span> <span class="s1">'W'</span>
<span class="o">[</span>31] <span class="o">=</span> <span class="s1">'e'</span>
<span class="o">[</span>32] <span class="o">=</span> <span class="s1">'d'</span>
<span class="o">[</span>33] <span class="o">=</span> <span class="s1">' '</span>
<span class="o">[</span>34] <span class="o">=</span> <span class="s1">'O'</span>
<span class="o">[</span>35] <span class="o">=</span> <span class="s1">'c'</span>
<span class="o">[</span>36] <span class="o">=</span> <span class="s1">'t'</span>
<span class="o">[</span>37] <span class="o">=</span> <span class="s1">' '</span>
<span class="o">[</span>38] <span class="o">=</span> <span class="s1">'1'</span>
<span class="o">[</span>39] <span class="o">=</span> <span class="s1">'0'</span>
<span class="o">[</span>40] <span class="o">=</span> <span class="s1">' '</span>
<span class="o">[</span>41] <span class="o">=</span> <span class="s1">'2'</span>
<span class="o">[</span>42] <span class="o">=</span> <span class="s1">'3'</span>
<span class="o">[</span>43] <span class="o">=</span> <span class="s1">':'</span>
<span class="o">[</span>44] <span class="o">=</span> <span class="s1">'0'</span>
<span class="o">[</span>45] <span class="o">=</span> <span class="s1">'6'</span>
<span class="o">[</span>46] <span class="o">=</span> <span class="s1">':'</span>
<span class="o">[</span>47] <span class="o">=</span> <span class="s1">'1'</span>
<span class="o">[</span>48] <span class="o">=</span> <span class="s1">'4'</span>
<span class="o">[</span>49] <span class="o">=</span> <span class="s1">' '</span>
<span class="o">[</span>50] <span class="o">=</span> <span class="s1">'P'</span>
<span class="o">[</span>51] <span class="o">=</span> <span class="s1">'D'</span>
<span class="o">[</span>52] <span class="o">=</span> <span class="s1">'T'</span>
<span class="o">[</span>53] <span class="o">=</span> <span class="s1">' '</span>
<span class="o">[</span>54] <span class="o">=</span> <span class="s1">'2'</span>
<span class="o">[</span>55] <span class="o">=</span> <span class="s1">'0'</span>
<span class="o">[</span>56] <span class="o">=</span> <span class="s1">'1'</span>
<span class="o">[</span>57] <span class="o">=</span> <span class="s1">'8'</span>
<span class="o">[</span>58] <span class="o">=</span> <span class="s1">';'</span>
<span class="o">[</span>59] <span class="o">=</span> <span class="s1">' '</span>
<span class="o">[</span>60] <span class="o">=</span> <span class="s1">'r'</span>
<span class="o">[</span>61] <span class="o">=</span> <span class="s1">'o'</span>
<span class="o">[</span>62] <span class="o">=</span> <span class="s1">'o'</span>
<span class="o">[</span>63] <span class="o">=</span> <span class="s1">'t'</span>
<span class="o">[</span>64] <span class="o">=</span> <span class="s1">':'</span>
<span class="o">[</span>65] <span class="o">=</span> <span class="s1">'x'</span>
<span class="o">[</span>66] <span class="o">=</span> <span class="s1">'n'</span>
<span class="o">[</span>67] <span class="o">=</span> <span class="s1">'u'</span>
<span class="o">[</span>68] <span class="o">=</span> <span class="s1">'-'</span>
<span class="o">[</span>69] <span class="o">=</span> <span class="s1">'4'</span>
<span class="o">[</span>70] <span class="o">=</span> <span class="s1">'5'</span>
<span class="o">[</span>71] <span class="o">=</span> <span class="s1">'7'</span>
<span class="o">[</span>72] <span class="o">=</span> <span class="s1">'0'</span>
<span class="o">[</span>73] <span class="o">=</span> <span class="s1">'.'</span>
<span class="o">[</span>74] <span class="o">=</span> <span class="s1">'7'</span>
<span class="o">[</span>75] <span class="o">=</span> <span class="s1">'1'</span>
<span class="o">[</span>76] <span class="o">=</span> <span class="s1">'.'</span>
<span class="o">[</span>77] <span class="o">=</span> <span class="s1">'1'</span>
<span class="o">[</span>78] <span class="o">=</span> <span class="s1">'3'</span>
<span class="o">[</span>79] <span class="o">=</span> <span class="s1">'~'</span>
<span class="o">[</span>80] <span class="o">=</span> <span class="s1">'1'</span>
<span class="o">[</span>81] <span class="o">=</span> <span class="s1">'/'</span>
<span class="o">[</span>82] <span class="o">=</span> <span class="s1">'D'</span>
<span class="o">[</span>83] <span class="o">=</span> <span class="s1">'E'</span>
<span class="o">[</span>84] <span class="o">=</span> <span class="s1">'V'</span>
<span class="o">[</span>85] <span class="o">=</span> <span class="s1">'E'</span>
<span class="o">[</span>86] <span class="o">=</span> <span class="s1">'L'</span>
<span class="o">[</span>87] <span class="o">=</span> <span class="s1">'O'</span>
<span class="o">[</span>88] <span class="o">=</span> <span class="s1">'P'</span>
<span class="o">[</span>89] <span class="o">=</span> <span class="s1">'M'</span>
<span class="o">[</span>90] <span class="o">=</span> <span class="s1">'E'</span>
<span class="o">[</span>91] <span class="o">=</span> <span class="s1">'N'</span>
<span class="o">[</span>92] <span class="o">=</span> <span class="s1">'T'</span>
<span class="o">[</span>93] <span class="o">=</span> <span class="s1">'_'</span>
<span class="o">[</span>94] <span class="o">=</span> <span class="s1">'X'</span>
<span class="o">[</span>95] <span class="o">=</span> <span class="s1">'8'</span>
<span class="o">[</span>96] <span class="o">=</span> <span class="s1">'6'</span>
<span class="o">[</span>97] <span class="o">=</span> <span class="s1">'_'</span>
<span class="o">[</span>98] <span class="o">=</span> <span class="s1">'6'</span>
<span class="o">[</span>99] <span class="o">=</span> <span class="s1">'4'</span>
<span class="o">[</span>100] <span class="o">=</span> <span class="s1">'\0'</span>
<span class="o">}</span>
<span class="o">(</span>lldb<span class="o">)</span>
</code></pre></div></div>
<p>Actually, using the <code class="high">x <address></code> command we can dumpt the memory contents at that address. Let’s do it.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">(</span>lldb<span class="o">)</span> x 0xffffff802f0f68f0
0xffffff802f0f68f0: 44 61 72 77 69 6e 20 4b 65 72 6e 65 6c 20 56 65 Darwin Kernel Ve
0xffffff802f0f6900: 72 73 69 6f 6e 20 31 37 2e 37 2e 30 3a 20 57 65 rsion 17.7.0: We
<span class="o">(</span>lldb<span class="o">)</span>
</code></pre></div></div>
<p>It looks like it continues to <code class="high">0xffffff802f0f6900</code>. Let’s dump that too.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">(</span>lldb<span class="o">)</span> x 0xffffff802f0f6900
0xffffff802f0f6900: 65 72 73 69 6f 6e 20 36 39 2e 30 30 20 57 65 65 rsion 17.7.0: We
0xffffff802f0f6910: 64 20 4f 63 74 20 31 30 20 32 33 3a 30 36 3a 31 d Oct 10 23:06:1
<span class="o">(</span>lldb<span class="o">)</span>
</code></pre></div></div>
<p>Nice! See the <code class="high">44 61 72 77 69 6e</code>? That is the hexadecimal representation of the word <code class="high">Darwin</code>. If we change that to let’s say “GeoSn0w” in HEX, we can pretty much change the kernel name. Same goes for the version. Let’s do it.</p>
<p>So, we need a Text to Hex converter. Many are available online. <a href="http://www.unit-conversion.info/texttools/hexadecimal/">I used this one</a>. And we need to keep in mind that we CANNOT write a longer string without overwriting something else. The word can be smaller and we can pad it with <code class="high">NOPs</code> (0x90) but not longer because it will overwrite stuff. I crafted my text to remove some stuff and add some stuff but I stayed in the same boundary. Don’t go past the character limit in the existing string.</p>
<p><b>My final hex looks like this:</b></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>47 65 6f 53 6e 30 77 20 4b 65 72 6e 65 6c 20 56 = "GeoSn0w Kernel V"
65 72 73 69 6f 6e 20 36 39 2e 30 30 20 57 65 65 = "ersion 69.00 Wee"
</code></pre></div></div>
<p>Now, we cannot write it to the two addresses like that. We have to add “0x” in front of all characters. The final result looks like this:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0x47 0x65 0x6f 0x53 0x6e 0x30 0x77 0x20 0x4b 0x65 0x72 0x6e 0x65 0x6c 0x20 0x56 = "GeoSn0w Kernel V"
0x65 0x72 0x73 0x69 0x6f 0x6e 0x20 0x36 0x39 0x2e 0x30 0x30 0x20 0x57 0x65 0x65 = "ersion 69.00 Wee"
</code></pre></div></div>
<p>Now we can write the bytes to the memory. Let’s start with the first address. In my case the command looks like this:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">(</span>lldb<span class="o">)</span> memory write 0xffffff802f0f68f0 0x47 0x65 0x6f 0x53 0x6e 0x30 0x77 0x20 0x4b 0x65 0x72 0x6e 0x65 0x6c 0x20 0x56
<span class="o">(</span>lldb<span class="o">)</span> x 0xffffff802f0f68f0
0xffffff802f0f68f0: 47 65 6f 53 6e 30 77 20 4b 65 72 6e 65 6c 20 56 GeoSn0w Kernel V
0xffffff802f0f6900: 72 73 69 6f 6e 20 31 37 2e 37 2e 30 3a 20 57 65 rsion 17.7.0: We
<span class="o">(</span>lldb<span class="o">)</span>
</code></pre></div></div>
<p>Now for the <code class="high">0xffffff802f0f6900</code> address to complete the string nicely:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">(</span>lldb<span class="o">)</span> memory write 0xffffff802f0f6900 0x65 0x72 0x73 0x69 0x6f 0x6e 0x20 0x36 0x39 0x2e 0x30 0x30 0x20 0x57 0x65 0x65
<span class="o">(</span>lldb<span class="o">)</span> x 0xffffff802f0f6900
0xffffff802f0f6900: 65 72 73 69 6f 6e 20 36 39 2e 30 30 20 57 65 65 ersion 69.00 Wee
0xffffff802f0f6910: 64 20 4f 63 74 20 31 30 20 32 33 3a 30 36 3a 31 d Oct 10 23:06:1
<span class="o">(</span>lldb<span class="o">)</span>
</code></pre></div></div>
<p>Now let’s unfreeze the kernel on the debugee:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">(</span>lldb<span class="o">)</span> c
Process 1 resuming
<span class="o">(</span>lldb<span class="o">)</span> Loading 1 kext modules warning: Can<span class="s1">'t find binary/dSYM for com.apple.driver.AppleXsanScheme (79D5E92F-789E-3C37-BE0E-7D1EAD697DD9)
. done.
Unloading 1 kext modules . done.
Unloading 1 kext modules . done.
(lldb)
</span></code></pre></div></div>
<p>And let’s run the <code class="high">uname -a</code> command in the Terminal of the debugee:</p>
<p align="center">
<img src="https://user-images.githubusercontent.com/15067741/49339564-0fc90580-f602-11e8-8142-49852c29a521.png" />
</p>
<p>And what do you know? It shows our string:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Last login: Sun Dec 2 07:12:19 on ttys000
Isabella:~ geosn0w<span class="nv">$ </span><span class="nb">uname</span> <span class="nt">-a</span>
Darwin Isabella.local 17.7.0 GeoSn0w Kernel Version 69.00 Weed Oct 10 23:06:14 PDT 2018<span class="p">;</span> root:xnu-4570.71.13~1/DEVELOPMENT_X86_64 x86_64
Isabella:~ geosn0w<span class="nv">$ </span>
</code></pre></div></div>
<p>And there you have it. Kernel debugging on macOS with some practical examples. I hope you enjoyed it. Do not forget that, after you’re done debugging stuff you should set the <code class="high">boot-args</code> back again to stock to boot the normal <code class="high">RELEASE</code> kernel. You do that by running the following command in Terminal on the debugee: <code class="high">sudo nvram boot-args=""</code>. Then go to <code class="high">/System/Library/Kernels/</code> and remove the <code class="high">kernel.development</code> file.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Isabella:~ geosn0w<span class="nv">$ </span><span class="nb">sudo </span>nvram boot-args<span class="o">=</span><span class="s2">""</span>
Password:
Isabella:~ geosn0w<span class="nv">$ </span>
</code></pre></div></div>
<p>Now in the Terminal write the following two commands to invalidate the kextcache:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo touch</span> /Library/Extensions
</code></pre></div></div>
<p>And</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo touch</span> /System/Library/Extensions
</code></pre></div></div>
<p>After this, perform a reboot and the computer will boot the normal <code class="high">RELEASE</code> kernel.</p>
<h3 id="errare-humanum-est">Errare humanum est</h3>
<p>If you found any horrible mistakes in this write-up, let me know on Twitter. My handle is @FCE365 (GeoSn0w). Thank you a lot for reading this!</p>
<h3 id="contact-me">Contact me</h3>
<ul>
<li>Twitter: https://twitter/FCE365</li>
<li>YouTube Channel: http://youtube.com/fce365official</li>
</ul>Hi there! It’s GeoSn0w. Debugging the damn kernel is a very entertaining thing to do (until you provoke a serious exception, that is, and the kernel crawls into a corner from which it refuses to get out). Unfortunately, it’s not an easy task nowadays and Apple seems to want to make it harder and harder. At first, by hiding under lock and key the documentation about the debug boot arguments, and then by moving the Kernel Debug Kit under the Developer Account-only Downloads section. There are many write-ups on the internet about debugging the kernel on macOS but many of them are outdated as hell and the NVRAM boot arguments they tell you to set are no longer working. Some of them stop at just the “now you should have a working debug session” - so what? what do I do next? I wanna have fun Goddammit! In this write-up I am doing my best to provide the most accurate information for 2019, the right commands, the right boot-args and of course, practical examples you can begin with.Jailbreaks Demystified2018-10-05T00:00:00+00:002018-10-05T00:00:00+00:00https://geosn0w.github.io/Jailbreaks-Demystified<p>The Jailbreaking process has long been a mysterious process where the iOS system suddenly gets unlocked out of Apple’s shackles after running an application for a few seconds. For a very long time, exactly what happened during the runtime of that application was largely unknown and even today as of iOS 11 (12 actually), the end-user (be that casual user, eta folk, reditter or nagger) remains largely oblivious about the processes going on. In this blog post, I am going to try to explain the main elements of a jailbreak as they were implemented and used historically. This post is not all-encompassing and various jailbreak tools for various iOS versions may use different patches and techniques, but they do boil down mostly to what you are about to read.</p>
<h3 id="why-jailbreak">Why Jailbreak?</h3>
<p>The nomenclature of the process likely comes from the Apple’s “Jailed” approach. Applications and users are bound to use only what Apple provides which is a fraction of what the device is capable of. Breaking this Jail of restrictions is the scope of the entire Jailbreak Process.</p>
<h3 id="for-the-eta-folk-reditter-nagger-et-al">For the eta folk, reditter, nagger, et. al.</h3>
<p>No, Cydia has nothing to do with Jailbreaking itself. Cydia is a byproduct of the jailbreak “community” and a jailbreak is not considered a jailbreak just because it has Cydia, just like a jailbreak that lacks Cydia is still a jailbreak. What differs is the target audience (or user).</p>
<p>Cydia is a GUI (Graphical User Interface) application which uses <code class="high">dpkg</code> and <code class="high">apt</code> (amongst others) in the background to install .deb (Debian) Packages. These packages follow a very strict (way too strict if you ask me) format that I will be discussing later. As the astute might have figured out, you don’t need Cydia to install packages. Since Cydia relies on apt and dpkg (etc), you can simply use these binaries via <code class="high">SSH</code> or through a mobile terminal application on the device. Cydia is just there to make this process as fool-proof as possible. Sometimes it fails.</p>
<p>So yes, my iOS 11.3.x/11.2.x Jailbreak, Osiris, released long before Electra was even a thing, was and is a jailbreak even though I never bundled any GUI installer (Cydia or such) with it. The same thing applies for LiberiOS by Jonathan Levin (iOS 11 to 11.1.2) which was maybe the most stable iOS 11 Jailbreak to date. These jailbreaks are mostly destined for researchers and power users and not the random eta folk (who usually flames at the lack of Cydia).</p>
<h3 id="so-how-does-it-work">So how does it work?</h3>
<p>Before being able to open Cydia, Installer 5, Icy Project, or an SSH on the device, the jailbreak has to run.
The stages of a jailbreak differ depending on the iOS version and the device. It used to be less reliant on the device type, but with the advent of KPP (Kernel Patch Protector) on iOS 9.0 and KTRR (allegedly Kernel Text Readonly Region) on iOS 10, that has become a thing more and more. For example, devices pre-iPhone 7 use KPP which is a software protection running in EL3 (ARM Exception LEVEL 3), but the iPhone 7 and newer are using KTRR which is hardware-based. In this case, a jailbreak containing only a KPP bypass (like Yalu) would not work on iPhone 7 and newer because KPP itself isn’t a thing there. Yalu, however, supports iPhone 7 thanks to @xerub and his “KPPLess” aproach. Normally, for these devices a KTRR bypass of sorts is required, as siguza has explained in his write-up aptly called <a href="http://siguza.github.io/KTRR/">KTRR</a>. So this way, the jailbreak tool has to know very well what kind of device it deals with.</p>
<h3 id="jailbreak-history-look-no-further-than-pangu-for-ios-7xx">Jailbreak History? Look no further than Pangu for iOS 7.x.x</h3>
<p>Before anything can happen on the device, the jailbreak payload has to be somehow deployed to the device. This may sound very trivial today because anybody has access to a free Apple Developer Account to sign an IPA file and install it on the device with Cydia Impactor or something akin to this, but it did not use to be this simple. This self-signing with Provisioning Profiles was introduced to the masses by Apple by iOS 9.0 which is not even that far back in the jailbreak history.</p>
<p>Long before that was a thing, <code class="high">CodeSign</code> was bypassed in very interesting ways by the highly skilled Jailbreak teams which are unfortunately long gone now. If you still have an iPhone 4 just collecting dust around, chances are you are jailbroken with Pangu for iOS 7.1 - 7.1.2. The astute can easily see that since this is talking about iOS 7.1.x, self-signing with provisioning profiles for free and deploying the signed IPAs was not a thing. So what was their trick?</p>
<p>Pangu for iOS 7.1- 7.1.2 has its own Windows and macOS program that does the deployment for you. The application it installs, aptly called “Pangu”, is signed with an enterprise certificate which existed at that point and was a powerful thing but it wasn’t as easy to obtain on the black market as it is today (hence the advent of all these signing services like Ignition and AppValley).</p>
<p>Their certificate was, however, expired. The Pangu program on the computer instructed the user to set the date and the time of the device way back to a date in 2014 (June 2, 2014, to be more specific).</p>
<p>The dummy application is deployed by the Pangu program and its main purpose is to drop that sweet certificate. The IPA itself is actually part of the Pangu Windows / macOS binary itself. That can easily be spotted by using any disassembler (I use Jtool and IDA).
Jtool by Jonathan Levin has a dope feature which can produce HTML output(!!!) which is very useful for when I build write-ups for my blog.</p>
<p>Here’s how the Pangu binary on macOS looks like. See the extra segments?</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> LC 00: LC_SEGMENT_64 Mem: 0x000000000-0x100000000 __PAGEZERO
LC 01: LC_SEGMENT_64 Mem: 0x100000000-0x101e71000 __TEXT
Mem: 0x100002370-0x1000292cf __TEXT.__text <span class="o">(</span>Normal<span class="o">)</span>
Mem: 0x1000292d0-0x10002982e __TEXT.__stubs <span class="o">(</span>Symbol Stubs<span class="o">)</span>
Mem: 0x100029830-0x10002a132 __TEXT.__stub_helper <span class="o">(</span>Normal<span class="o">)</span>
Mem: 0x10002a140-0x10002a690 __TEXT.__const
Mem: 0x10002a690-0x10002b914 __TEXT.__objc_methname <span class="o">(</span>C-String Literals<span class="o">)</span>
Mem: 0x10002b914-0x10002b9d5 __TEXT.__objc_classname <span class="o">(</span>C-String Literals<span class="o">)</span>
Mem: 0x10002b9d5-0x10002beb6 __TEXT.__objc_methtype <span class="o">(</span>C-String Literals<span class="o">)</span>
Mem: 0x10002bec0-0x10002e8d5 __TEXT.__cstring <span class="o">(</span>C-String Literals<span class="o">)</span>
Mem: 0x10002e8d6-0x10002e92e __TEXT.__ustring
Mem: 0x10002e92e-0x10003dc04 __TEXT.__objc_cons1
Mem: 0x10003dc04-0x10029ed87 __TEXT.__objc_cons2 <span class="p">;</span> Yeee, see this!
Mem: 0x10029ed87-0x1002b71a9 __TEXT.__objc_cons3
Mem: 0x1002b71a9-0x100f11a36 __TEXT.__objc_cons4
Mem: 0x100f11a36-0x10160e0ca __TEXT.__objc_cons5
Mem: 0x10160e0ca-0x101dd6e3f __TEXT.__objc_cons6
Mem: 0x101dd6e3f-0x101dd7152 __TEXT.__objc_cons7
Mem: 0x101dd7152-0x101dd7a17 __TEXT.__objc_cons8
Mem: 0x101dd7a17-0x101e45a6e __TEXT.__objc_cons9
Mem: 0x101e45a6e-0x101e57e74 __TEXT.__objc_cons10
Mem: 0x101e57e74-0x101e69288 __TEXT.__objc_cons11
Mem: 0x101e69288-0x101e699e0 __TEXT.__unwind_info
Mem: 0x101e699e0-0x101e71000 __TEXT.__eh_frame
LC 02: LC_SEGMENT_64 Mem: 0x101e71000-0x101e75000 __DATA
Mem: 0x101e71000-0x101e71028 __DATA.__program_vars
Mem: 0x101e71028-0x101e710b8 __DATA.__got <span class="o">(</span>Non-Lazy Symbol Ptrs<span class="o">)</span>
Mem: 0x101e710b8-0x101e710c8 __DATA.__nl_symbol_ptr <span class="o">(</span>Non-Lazy Symbol Ptrs<span class="o">)</span>
Mem: 0x101e710c8-0x101e717f0 __DATA.__la_symbol_ptr <span class="o">(</span>Lazy Symbol Ptrs<span class="o">)</span>
Mem: 0x101e717f0-0x101e717f8 __DATA.__mod_init_func <span class="o">(</span>Module Init Function Ptrs<span class="o">)</span>
Mem: 0x101e717f8-0x101e71800 __DATA.__mod_term_func <span class="o">(</span>Module Termination Function Ptrs<span class="o">)</span>
Mem: 0x101e71800-0x101e71b40 __DATA.__const
Mem: 0x101e71b40-0x101e71b60 __DATA.__objc_classlist <span class="o">(</span>Normal<span class="o">)</span>
Mem: 0x101e71b60-0x101e71b68 __DATA.__objc_nlclslist <span class="o">(</span>Normal<span class="o">)</span>
Mem: 0x101e71b68-0x101e71b78 __DATA.__objc_catlist <span class="o">(</span>Normal<span class="o">)</span>
Mem: 0x101e71b78-0x101e71ba0 __DATA.__objc_protolist
Mem: 0x101e71ba0-0x101e71ba8 __DATA.__objc_imageinfo
Mem: 0x101e71ba8-0x101e72f90 __DATA.__objc_const
Mem: 0x101e72f90-0x101e73590 __DATA.__objc_selrefs <span class="o">(</span>Literal Pointers<span class="o">)</span>
Mem: 0x101e73590-0x101e735a0 __DATA.__objc_protorefs
Mem: 0x101e735a0-0x101e736f8 __DATA.__objc_classrefs <span class="o">(</span>Normal<span class="o">)</span>
Mem: 0x101e736f8-0x101e73718 __DATA.__objc_superrefs <span class="o">(</span>Normal<span class="o">)</span>
Mem: 0x101e73718-0x101e738a8 __DATA.__objc_data
Mem: 0x101e738a8-0x101e73930 __DATA.__objc_ivar
Mem: 0x101e73930-0x101e74390 __DATA.__cfstring
Mem: 0x101e74390-0x101e746b8 __DATA.__data
Mem: 0x101e746c0-0x101e74b60 __DATA.__bss <span class="o">(</span>Zero Fill<span class="o">)</span>
Mem: 0x101e74b60-0x101e74b90 __DATA.__common <span class="o">(</span>Zero Fill<span class="o">)</span>
LC 03: LC_SEGMENT_64 Mem: 0x101e75000-0x101eba000 __ui0
LC 04: LC_SEGMENT_64 Mem: 0x101eba000-0x101ebf000 __LINKEDIT
LC 05: LC_DYLD_INFO
LC 06: LC_SYMTAB
Symbol table is at offset 0x1ebbc48 <span class="o">(</span>32226376<span class="o">)</span>, 293 entries
String table is at offset 0x1ebd610 <span class="o">(</span>32232976<span class="o">)</span>, 4776 bytes
....
</code></pre></div></div>
<p>Do you see the <code class="high">__TEXT.__objc_cons2 section</code>?</p>
<p>If you do <code class="high">0x10029ed87 - 0x10003dc04 = 2494851 bytes (decimal) => 2.494851 Megabytes</code>.
That is hell of a big section. No wonder, It is the embedded IPA file. objc_cons1, objc_cons2 and objc_cons3 are all embedded parts of the jailbreak payload (the untether, plists, libraries etc).</p>
<p>In fact, let’s not talk about it, let’s see it!</p>
<p>Jtool is a very powerful tool. It has the ability to extract whole sections from a binary. The command is <code class="high">jtool -e (extract) /path</code>.
If we do that to the Pangu binary we will get a new file called <code class="high">pangu.__TEXT.__objc_cons2</code> which so happens to be identified by the <code class="high">file(1)</code> as being a <code class="high">gzip compressed data, from Unix</code>, so a <code class="high">tar tvf</code> should be able to list the contents quite fine.
It can and it does.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Saigon:~ geosn0w<span class="nv">$ </span>/Users/geosn0w/Desktop/ToolChain/jtool/jtool <span class="nt">-e</span> __TEXT.__objc_cons2 /Users/geosn0w/Desktop/pangu.app/Contents/MacOS/pangu
Requested section found at Offset 252932
Extracting __TEXT.__objc_cons2 at 252932, 2494851 <span class="o">(</span>261183<span class="o">)</span> bytes into pangu.__TEXT.__objc_cons2
Saigon:~ geosn0w<span class="nv">$ </span>file /Users/geosn0w/pangu.__TEXT.__objc_cons2
/Users/geosn0w/pangu.__TEXT.__objc_cons2: <span class="nb">gzip </span>compressed data, from Unix
Saigon:~ geosn0w<span class="nv">$ </span><span class="nb">tar </span>tvf /Users/geosn0w/pangu.__TEXT.__objc_cons2
drwxrwxrwx 0 0 0 0 Jun 27 2014 Payload/
drwxrwxrwx 0 0 0 0 Jun 27 2014 Payload/ipa1.app/
drwxrwxrwx 0 0 0 0 Jun 27 2014 Payload/ipa1.app/_CodeSignature/
<span class="nt">-rwxrwxrwx</span> 0 0 0 3638 Jun 27 2014 Payload/ipa1.app/_CodeSignature/CodeResources
<span class="nt">-rwxrwxrwx</span> 0 0 0 15112 Jun 27 2014 Payload/ipa1.app/AppIcon60x60@2x.png
<span class="nt">-rwxrwxrwx</span> 0 0 0 20753 Jun 27 2014 Payload/ipa1.app/AppIcon76x76@2x~ipad.png
<span class="nt">-rwxrwxrwx</span> 0 0 0 8017 Jun 27 2014 Payload/ipa1.app/AppIcon76x76~ipad.png
<span class="nt">-rwxrwxrwx</span> 0 0 0 75320 Jun 27 2014 Payload/ipa1.app/Assets.car
<span class="nt">-rwxrwxrwx</span> 0 0 0 7399 Jun 27 2014 Payload/ipa1.app/embedded.mobileprovision
drwxrwxrwx 0 0 0 0 Jun 27 2014 Payload/ipa1.app/en.lproj/
<span class="nt">-rwxrwxrwx</span> 0 0 0 74 Jun 27 2014 Payload/ipa1.app/en.lproj/InfoPlist.strings
<span class="nt">-rwxrwxrwx</span> 0 0 0 1955 Jun 27 2014 Payload/ipa1.app/Info.plist
<span class="nt">-rwxrwxrwx</span> 0 0 0 312208 Jun 27 2014 Payload/ipa1.app/ipa1
<span class="nt">-rwxrwxrwx</span> 0 0 0 968 Jun 27 2014 Payload/ipa1.app/ipa1-Info.plist
<span class="nt">-rwxrwxrwx</span> 0 0 0 235794 Jun 27 2014 Payload/ipa1.app/LaunchImage-700-568h@2x.png
<span class="nt">-rwxrwxrwx</span> 0 0 0 785321 Jun 27 2014 Payload/ipa1.app/LaunchImage-700-Landscape@2x~ipad.png
<span class="nt">-rwxrwxrwx</span> 0 0 0 261481 Jun 27 2014 Payload/ipa1.app/LaunchImage-700-Landscape~ipad.png
<span class="nt">-rwxrwxrwx</span> 0 0 0 660541 Jun 27 2014 Payload/ipa1.app/LaunchImage-700-Portrait@2x~ipad.png
<span class="nt">-rwxrwxrwx</span> 0 0 0 244644 Jun 27 2014 Payload/ipa1.app/LaunchImage-700-Portrait~ipad.png
<span class="nt">-rwxrwxrwx</span> 0 0 0 216627 Jun 27 2014 Payload/ipa1.app/LaunchImage-700@2x.png
<span class="nt">-rwxrwxrwx</span> 0 0 0 8 Jun 27 2014 Payload/ipa1.app/PkgInfo
<span class="nt">-rwxrwxrwx</span> 0 0 0 150 Jun 27 2014 Payload/ipa1.app/ResourceRules.plist
drwxrwxrwx 0 0 0 0 Jun 27 2014 Payload/ipa1.app/zh-Hans.lproj/
<span class="nt">-rwxrwxrwx</span> 0 0 0 73 Jun 27 2014 Payload/ipa1.app/zh-Hans.lproj/InfoPlist.strings
Saigon:~ geosn0w<span class="nv">$ </span>
</code></pre></div></div>
<p>Doing a <code class="high">tar xvf</code> will extract the contents to a “Payload” folder.
So the IPA file that gets deployed on the phone is actually ipa1. As you can see, there is a file called <code class="high">embedded.mobileprovision</code> which contains the enterprise certificate. If we Right-click on it and select “Get Info”, Finder is capable to show us some information about the embedded certificate. As you can see, it belongs to “Hefei Bo Fang”, whatever that is.</p>
<p align="center">
<img src="https://user-images.githubusercontent.com/15067741/46533169-a763df00-c871-11e8-884b-fa51df3b0f6e.png" />
</p>
<h3 id="getting-there">Getting there…</h3>
<p>As you can see, Pangu, like many other jailbreaks relied on developer certificate to bypass the CodeSign, but getting the IPA deployed to the device is not as easy as you may think. Nowadays we quickly fire Cydia Impactor, drag and drop the IPA, sign in and there we go. This wasn’t the case until iOS 9.0, so Pangu had to do what other jailbreak teams before them did - use Apple against itself.</p>
<p>iTunes can easily communicate with the device and up until iTunes 12.x, iTunes was capable to handle iOS applications too. It was since stripped off this functionality but that hinted to the fact that one or more frameworks (or DLLs for the Windows folk) have to be able to create a connection to the device and perform application-related tasks. Of course, we are talking about AppleMobileDevice.(framework / dll). Shipped with iTunes and its driver packages, this framework was largely used in the jailbreaks before and it is still used by all these “Backup iOS / Photos / Contacts / Whatever” programs on Windows to communicate reliably with the device. The APIs are, of course, private but they were reversed to shit and beyond by multiple researchers. They were also recreated in the <code class="high">libimobiledevice</code> project.</p>
<p>As you can see, with that in place, Pangu could finally talk to the device and drop the payload at the right moment.
The rest follows an almost formulaic set of canonical patches I am going to discuss below.</p>
<p>Pangu was my desired example here because it is fairly new so it applies most of the following patches (compared to redsn0w etc) and also because it is one of the jailbreaks I have used myself a lot on an iPhone 4 I still happen to have.</p>
<p>I mostly gave it as an example so that you can see the difference between getting to bypass CodeSign back then vs getting to bypass CodeSign now.</p>
<h3 id="canonical-patches">Canonical Patches</h3>
<p>I have created the following diagram which should (in theory) show the flow of most jailbreaks. Of course, the implementation and techniques would be different from iOS version to iOS version and some jailbreaks may do the actions in a totally different order.</p>
<p align="center">
<img src="https://user-images.githubusercontent.com/15067741/46557813-31836600-c8b9-11e8-9171-116a8ea7f939.png" />
</p>
<p>So, as you can see from the diagram, the most important step is getting on the device. You cannot do much from outside the device. The entry vector can be different from jailbreak to jailbreak. Nowadays, most jailbreaks including my Osiris, Coolstar & Co’s Electra and Jonathan’s LiberiOS use the IPA applications signed with a temporary certificate and deployed with either Xcode or Cydia Impactor (or a signing service) to the device. From there, the application is executed by the user and the exploit is triggered.</p>
<p>Other methods include but are not limited to WebKit exploits, mail exploits, etc.
The WebKit ones are more common. <i>TotallyNotSpyware*</i> is a good example of an iOS 10.x to 10.3.3 64-Bit Jailbreak, and if we talk legacy, JailbreakMe series is probably the best example. These WebKit-based jailbreaks are usually deployed by accessing a website in Safari on the device. The website is crafted so that it exploits a webkit vulnerability (WebKit is at Safari’s core), and thus gaining arbitrary code execution.</p>
<p>In the rest of this write-up, I will assume an IPA based Jailbreak like Osiris, LiberiOS or Electra. Also, this write-up assumes we already have a raw kernel exploit that gives us <code class="high">TFP0</code>, and the KPPless approach.</p>
<p>After the application has been successfully installed and can run, CodeSign is no longer a problem, at least for the initial stage. We still cannot run unsigned or fake-signed binaries, but at least we can run ourselves (the exploit application) without being killed by AMFI. However, the problem is that we are still limited by the SandBox. The SandBox keeps us from accessing anything outside our container, so no R/W permissions for us. All we can see is our own data, nothing more. That has to change. We have to bestow ourselves the might of ShaiHulud!</p>
<p>The SandBox is a kernel extension (KEXT) which ensures that you do not access more than you’re supposed to access. By default, everything in /var/mobile/Containers is sandboxed. Apple’s own default applications are also sandboxed. When you install an application via Xcode, the App Store or via Cydia Impactor, you are automatically placing the application in <code class="high">/var/mobile/Containers/Bundle/Application/UUID of the APP</code>. There is no other way to install an app, so our jailbreak application will be sandboxed by default, no matter what.</p>
<p>So how do apps have access to the services required in order for them to run?! How can Deezer connect to my Bluetooth headset? How can YouTube decode frames? How can Twitter send me notifications? It’s simple, through APIs. These APIs allow your containerized app to communicate in a controlled manner with Core Services (<code class="high">bluetoothd</code>, <code class="high">wifid</code>, <code class="high">mediaserverd</code>, etc) which are also sandboxed, and these Core Services talk with the kexts / kernel through <code class="high">IOKit</code>. So no, you don’t directly talk to the kernel. The following diagram should help you see how this looks like.</p>
<p align="center">
<img src="https://user-images.githubusercontent.com/15067741/46547236-4fd96980-c899-11e8-8d48-1947418eb777.png" />
</p>
<p>Of course, as an Application on iOS, not only you cannot see the File System and the User Data, but you are also largely oblivious of the existence of any other applications. Yes, through some APIs you can pass files / data to another application if that other application is registered as one that accepts to handle such input, but even then, you as an application don’t know anything about the existence of the other app and it is through the series of APIs provided by iOS that you pass your .PDF file, for example, to be opened in whatever application.</p>
<p>Some applications also provide uri schemes for you to communicate with them. Let’s say you are in Chrome on iOS and you find a phone number to a company you wanna call. If you press it, you get asked if you really wanna call, and then you go straight to the Call app from iOS and the number is already being dialed. How?</p>
<p>Simple. The “Phone” application has registered an uri scheme that looks like this: <code class="high">tel://XXXXXXXXXXXX</code> so if you add <code class="high">tel://5552220001</code> to an HTML page and click it in Safari, the iOS knows who to open to handle that. Same goes for Facebook, WhatsApp, etc.</p>
<p>To use the URI scheme from your app, you just have to call the right UIApplication method. That is</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">UIApplication</span><span class="o">.</span><span class="n">shared</span><span class="o">.</span><span class="nf">open</span><span class="p">(</span><span class="n">url</span><span class="p">,</span> <span class="nv">options</span><span class="p">:</span> <span class="p">[:],</span> <span class="nv">completionHandler</span><span class="p">:</span> <span class="kc">nil</span><span class="p">)</span>
</code></pre></div></div>
<p>So does that mean you bypassed SandBox because you were able to pass data to another app and open it? Not even close. All you did was through a very well controlled set of APIs. You don’t know that Phone app exists. iOS knows.
Here’s how SandBoxing feels for an application.</p>
<p align="center">
<img src="https://user-images.githubusercontent.com/15067741/46547949-9760f500-c89b-11e8-966a-fef2dbfb28d9.png" />
</p>
<p>SandBox escaping can be done in multiple ways.</p>
<p>Osiris Jailbreak uses QiLin’s built-in SandBox escape which is called “ShaiHulud”, a Dune reference.</p>
<p>QiLin (and therefore LiberiOS and Osiris Jailbreak) escape the SandBox by assuming Kernel’s credentials. Not only that, but since now we have the Kernel’s credentials, we have access to whatever we want including syscalls like execve(), fork(), and posix_spawn()! Jonathan Levin has explained very well how QiLin proceeds in escaping the sandbox and assuming the kernel creds <a href="http://newosxbook.com/QiLin/qilin.pdf"> in this write-up</a>, part of the <code class="high"><a href="https://www.amazon.com/MacOS-iOS-Internals-III-Insecurity/dp/0991055535/ref=as_sl_pc_qf_sp_asin_til?tag=newosxbookcom-20&linkCode=w00&linkId=0b61c945365c9c37cd3cf88f10a5f629&creativeASIN=0991055535">*OS Internals Volume III</a></code></p>
<p>Of course, QiLin saves our application’s credentials and restores them before exiting, that is to prevent creating panics due to the various locks that govern the kernel creds (and by increasing the wrong reference counters).</p>
<p>Electra for iOS 11.2.x -> iOS 11.3.1 also uses the same kernel credential method for sandbox bypass and other privs.</p>
<h3 id="running-fake-signed-binaries-the-alpha-and-omega-of-a-jailbreak">Running fake-signed binaries, the Alpha and Omega of a Jailbreak</h3>
<p>A Jailbreak doesn’t provide much of a value if it doesn’t come with a binary pack, part of what is called the “bootstrap”. This binary pack can often contain a long set of command-line (CLI) binaries that one can use either programatically or via an SSH connection. These binaries include but are not limited to binaries that: rename, move, remove files, SSH clients like dropbear and their dependencies, various shells like <code class="high">ZSH</code>, archive utilities like <code class="high">gzip</code> and the standard <code class="high">chown</code>, <code class="high">chmod</code> and <code class="high">chflags</code> for messing with files permissions and such.</p>
<p><b>NOTA BENE! Please do not confuse <code class="high">bootstrap</code> with <code class="high">bin pack</code> or <code class="high">base binaries</code>. The base binaries are the jailbreak-specific daemons or additional binaries and may change from a jailbreak to another. The <code class="high">bin pack</code> is part of a <code class="high">Boostrap</code>, and a <code class="high">Bootstrap</code> contains Cydia, the CLI tools, Cydia dependencies and any other support files for it. Just like the <code class="high">base binaries</code>, the content of the <code class="high">Bootstrap</code> can also vary. For example, pwn20wnd’s version of Osiris he rewrote from scratch doesn’t contain Cydia in its bootstrap but it contains Filza.</b></p>
<p>Across the history of jailbreaks, various jailbreak teams have built their own binary packs in the .tar format which they deployed and extracted once they had access to the root file system which we discuss below.</p>
<p>On iOS 11.x which is 64-Bit, there is a very well made universal binary pack created by Jonathan Levin and published on <a href="http://newosxbook.com/tools/iOSBinaries.html">NewOSXBook</a> that can be used in any iOS 11 Jailbreak. The binpack contains a ton of binaries for various purposes, including an ARM compiled version of jtool to mess with the signatures and disassemble on the device.</p>
<p>The following is the content of the binpack by Jonathan Levin used in his LiberiOS Jailbreak for iOS 11.x and my Osiris Jailbreak for iOS 11.2.x</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Saigon:~ geosn0w<span class="nv">$ </span><span class="nb">tar </span>tvf /Users/geosn0w/Desktop/binpack64-256.tar.gz
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 54736 Apr 25 17:55 amfidebilitate
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Mar 18 2018 ./._bin
drwxr-xr-x 0 morpheus staff 0 Mar 18 2018 bin/
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:45 bin/._cat
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 52672 Apr 25 17:45 bin/cat
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:45 bin/._launchctl
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 127488 Apr 25 17:45 bin/launchctl
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:45 bin/._pwd
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 50944 Apr 25 17:45 bin/pwd
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:45 bin/._sleep
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 50736 Apr 25 17:45 bin/sleep
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:45 bin/._stty
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 53984 Apr 25 17:45 bin/stty
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:45 bin/._date
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 53952 Apr 25 17:45 bin/date
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:45 bin/._bash
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 1038208 Apr 25 17:45 bin/bash
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:45 bin/._kill
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 51376 Apr 25 17:45 bin/kill
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:45 bin/._sh
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 669664 Apr 25 17:45 bin/sh
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:45 bin/._dd
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 70769 Apr 25 17:45 bin/dd
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:45 bin/._mkdir
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 51312 Apr 25 17:45 bin/mkdir
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:45 bin/._hostname
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 50960 Apr 25 17:45 bin/hostname
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:45 bin/._rmdir
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 50912 Apr 25 17:45 bin/rmdir
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:45 bin/._mv
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 53056 Apr 25 17:45 bin/mv
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:45 bin/._ln
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 51936 Apr 25 17:45 bin/ln
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:45 bin/._ls
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 74656 Apr 25 17:45 bin/ls
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:45 bin/._cp
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 53872 Apr 25 17:45 bin/cp
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:45 bin/._sync
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 50448 Apr 25 17:45 bin/sync
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:45 bin/._zsh
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 669664 Apr 25 17:45 bin/zsh
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:45 bin/._chmod
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 55328 Apr 25 17:45 bin/chmod
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:45 bin/._rm
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 53392 Apr 25 17:45 bin/rm
<span class="nt">-rw-r--r--</span> 0 morpheus staff 271 Apr 25 17:45 default.ent
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 11 22:36 ./._etc
drwxr-xr-x 0 morpheus staff 0 Apr 11 22:36 etc/
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Dec 20 2017 etc/._ssl
lrwxr-xr-x 0 morpheus staff 0 Dec 20 2017 etc/ssl -> ../usr/
<span class="nt">-r--r--r--</span> 0 morpheus staff 178 Apr 11 22:36 etc/._zshrc
<span class="nt">-r--r--r--</span> 0 morpheus staff 2770 Apr 11 22:36 etc/zshrc
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Mar 4 2016 etc/._dropbear
drwxr-xr-x 0 morpheus staff 0 Mar 4 2016 etc/dropbear/
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Mar 4 2016 etc/._profile
<span class="nt">-rw-r--r--</span> 0 morpheus staff 92 Mar 4 2016 etc/profile
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Mar 18 2018 etc/._apt
drwxr-xr-x 0 morpheus staff 0 Mar 18 2018 etc/apt/
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Mar 18 2018 etc/._alternatives
drwxr-xr-x 0 morpheus staff 0 Mar 18 2018 etc/alternatives/
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Mar 18 2018 etc/._dpkg
drwxr-xr-x 0 morpheus staff 0 Mar 18 2018 etc/dpkg/
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Jan 18 2018 etc/._motd
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1012 Jan 18 2018 etc/motd
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Dec 20 2017 etc/dpkg/._dselect.cfg.d
drwxr-xr-x 0 morpheus staff 0 Dec 20 2017 etc/dpkg/dselect.cfg.d/
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Dec 20 2017 etc/dpkg/._dpkg.cfg.d
drwxr-xr-x 0 morpheus staff 0 Dec 20 2017 etc/dpkg/dpkg.cfg.d/
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Dec 20 2017 etc/alternatives/._README
<span class="nt">-rw-r--r--</span> 0 morpheus staff 100 Dec 20 2017 etc/alternatives/README
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Mar 18 2018 etc/apt/._sources.list.d
drwxr-xr-x 0 morpheus staff 0 Mar 18 2018 etc/apt/sources.list.d/
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Mar 18 2018 etc/apt/._trusted.gpg.d
drwxr-xr-x 0 morpheus staff 0 Mar 18 2018 etc/apt/trusted.gpg.d/
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Feb 3 2017 etc/apt/trusted.gpg.d/._zodttd.gpg
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1158 Feb 3 2017 etc/apt/trusted.gpg.d/zodttd.gpg
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Feb 3 2017 etc/apt/trusted.gpg.d/._bigboss.gpg
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1164 Feb 3 2017 etc/apt/trusted.gpg.d/bigboss.gpg
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Feb 3 2017 etc/apt/trusted.gpg.d/._modmyi.gpg
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1180 Feb 3 2017 etc/apt/trusted.gpg.d/modmyi.gpg
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Feb 3 2017 etc/apt/trusted.gpg.d/._saurik.gpg
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1172 Feb 3 2017 etc/apt/trusted.gpg.d/saurik.gpg
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Feb 3 2017 etc/apt/sources.list.d/._cydia.list
<span class="nt">-rw-r--r--</span> 0 morpheus staff 0 Feb 3 2017 etc/apt/sources.list.d/cydia.list
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Feb 3 2017 etc/apt/sources.list.d/._saurik.list
<span class="nt">-rw-r--r--</span> 0 morpheus staff 227 Feb 3 2017 etc/apt/sources.list.d/saurik.list
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Jan 3 2018 ./._makeMeAtHome.sh
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 729 Jan 3 2018 makeMeAtHome.sh
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 952 Mar 19 2018 removeMe.sh
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 18:24 ./._sbin
drwxr-xr-x 0 morpheus staff 0 Apr 25 18:24 sbin/
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:45 sbin/._md5
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 54016 Apr 25 17:45 sbin/md5
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:45 sbin/._ping
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 72528 Apr 25 17:45 sbin/ping
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:45 sbin/._shutdown
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 54704 Apr 25 17:45 sbin/shutdown
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:45 sbin/._ifconfig
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 111696 Apr 25 17:45 sbin/ifconfig
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 53616 Apr 25 18:24 sbin/umount
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:53 sbin/._kextunload
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 76256 Apr 25 17:53 sbin/kextunload
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:45 sbin/._mknod
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 51504 Apr 25 17:45 sbin/mknod
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:45 sbin/._dmesg
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 50912 Apr 25 17:45 sbin/dmesg
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Mar 18 2018 ./._usr
drwxr-xr-x 0 morpheus staff 0 Mar 18 2018 usr/
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:46 usr/._bin
drwxr-xr-x 0 morpheus staff 0 Apr 25 17:46 usr/bin/
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Mar 18 2018 usr/._sbin
drwxr-xr-x 0 morpheus staff 0 Mar 18 2018 usr/sbin/
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Mar 18 2018 usr/._local
drwxr-xr-x 0 morpheus staff 0 Mar 18 2018 usr/local/
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Mar 18 2018 usr/._share
drwxr-xr-x 0 morpheus staff 0 Mar 18 2018 usr/share/
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Mar 18 2018 usr/share/._terminfo
drwxr-xr-x 0 morpheus staff 0 Mar 18 2018 usr/share/terminfo/
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Mar 18 2018 usr/share/terminfo/._61
drwxr-xr-x 0 morpheus staff 0 Mar 18 2018 usr/share/terminfo/61/
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Mar 18 2018 usr/share/terminfo/._73
drwxr-xr-x 0 morpheus staff 0 Mar 18 2018 usr/share/terminfo/73/
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Mar 18 2018 usr/share/terminfo/._6c
drwxr-xr-x 0 morpheus staff 0 Mar 18 2018 usr/share/terminfo/6c/
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Mar 18 2018 usr/share/terminfo/._76
drwxr-xr-x 0 morpheus staff 0 Mar 18 2018 usr/share/terminfo/76/
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Mar 18 2018 usr/share/terminfo/._78
drwxr-xr-x 0 morpheus staff 0 Mar 18 2018 usr/share/terminfo/78/
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/78/._xterm-256color
<span class="nt">-rw-r--r--</span> 0 morpheus staff 3322 Sep 9 2014 usr/share/terminfo/78/xterm-256color
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Mar 4 2016 usr/share/terminfo/76/._vt100-putty
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1199 Mar 4 2016 usr/share/terminfo/76/vt100-putty
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Mar 4 2016 usr/share/terminfo/76/._vt100-nav-w
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1093 Mar 4 2016 usr/share/terminfo/76/vt100-nav-w
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Mar 4 2016 usr/share/terminfo/76/._vt100-s
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1272 Mar 4 2016 usr/share/terminfo/76/vt100-s
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Mar 4 2016 usr/share/terminfo/76/._vt100+
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1657 Mar 4 2016 usr/share/terminfo/76/vt100+
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Mar 4 2016 usr/share/terminfo/76/._vt100nam
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1190 Mar 4 2016 usr/share/terminfo/76/vt100nam
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Mar 4 2016 usr/share/terminfo/76/._vt100-vb
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1207 Mar 4 2016 usr/share/terminfo/76/vt100-vb
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Mar 4 2016 usr/share/terminfo/76/._vt100+enq
<span class="nt">-rw-r--r--</span> 0 morpheus staff 682 Mar 4 2016 usr/share/terminfo/76/vt100+enq
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Mar 4 2016 usr/share/terminfo/76/._vt100-s-top
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1272 Mar 4 2016 usr/share/terminfo/76/vt100-s-top
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Mar 4 2016 usr/share/terminfo/76/._vt100-nam-w
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1221 Mar 4 2016 usr/share/terminfo/76/vt100-nam-w
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Mar 4 2016 usr/share/terminfo/76/._vt100+fnkeys
<span class="nt">-rw-r--r--</span> 0 morpheus staff 450 Mar 4 2016 usr/share/terminfo/76/vt100+fnkeys
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Mar 4 2016 usr/share/terminfo/76/._vt100-w
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1203 Mar 4 2016 usr/share/terminfo/76/vt100-w
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Mar 4 2016 usr/share/terminfo/76/._vt100
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1194 Mar 4 2016 usr/share/terminfo/76/vt100
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Mar 4 2016 usr/share/terminfo/76/._vt100-w-nav
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1093 Mar 4 2016 usr/share/terminfo/76/vt100-w-nav
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Mar 4 2016 usr/share/terminfo/76/._vt100-bot-s
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1256 Mar 4 2016 usr/share/terminfo/76/vt100-bot-s
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Mar 4 2016 usr/share/terminfo/76/._vt100-w-nam
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1221 Mar 4 2016 usr/share/terminfo/76/vt100-w-nam
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Mar 4 2016 usr/share/terminfo/76/._vt100+pfkeys
<span class="nt">-rw-r--r--</span> 0 morpheus staff 422 Mar 4 2016 usr/share/terminfo/76/vt100+pfkeys
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Mar 4 2016 usr/share/terminfo/76/._vt100-top-s
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1272 Mar 4 2016 usr/share/terminfo/76/vt100-top-s
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Mar 4 2016 usr/share/terminfo/76/._vt100-nav
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1059 Mar 4 2016 usr/share/terminfo/76/vt100-nav
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Mar 4 2016 usr/share/terminfo/76/._vt100-nam
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1190 Mar 4 2016 usr/share/terminfo/76/vt100-nam
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Mar 4 2016 usr/share/terminfo/76/._vt100-bm-o
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1207 Mar 4 2016 usr/share/terminfo/76/vt100-bm-o
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Mar 4 2016 usr/share/terminfo/76/._vt100+keypad
<span class="nt">-rw-r--r--</span> 0 morpheus staff 368 Mar 4 2016 usr/share/terminfo/76/vt100+keypad
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Mar 4 2016 usr/share/terminfo/76/._vt100-am
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1194 Mar 4 2016 usr/share/terminfo/76/vt100-am
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Mar 4 2016 usr/share/terminfo/76/._vt100-s-bot
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1256 Mar 4 2016 usr/share/terminfo/76/vt100-s-bot
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Mar 4 2016 usr/share/terminfo/76/._vt100-w-am
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1203 Mar 4 2016 usr/share/terminfo/76/vt100-w-am
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Mar 4 2016 usr/share/terminfo/76/._vt100-bm
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1201 Mar 4 2016 usr/share/terminfo/76/vt100-bm
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/6c/._linux-lat
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1782 Sep 9 2014 usr/share/terminfo/6c/linux-lat
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/6c/._linux-koi8r
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1774 Sep 9 2014 usr/share/terminfo/6c/linux-koi8r
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/6c/._linux-vt
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1652 Sep 9 2014 usr/share/terminfo/6c/linux-vt
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/6c/._linux-basic
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1626 Sep 9 2014 usr/share/terminfo/6c/linux-basic
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/6c/._linux
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1740 Sep 9 2014 usr/share/terminfo/6c/linux
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/6c/._linux-c-nc
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1726 Sep 9 2014 usr/share/terminfo/6c/linux-c-nc
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/6c/._linux2.6.26
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1752 Sep 9 2014 usr/share/terminfo/6c/linux2.6.26
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/6c/._linux-c
<span class="nt">-rw-r--r--</span> 0 morpheus staff 2080 Sep 9 2014 usr/share/terminfo/6c/linux-c
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/6c/._linux-m
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1730 Sep 9 2014 usr/share/terminfo/6c/linux-m
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/6c/._linux-nic
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1772 Sep 9 2014 usr/share/terminfo/6c/linux-nic
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/6c/._linux-koi8
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1768 Sep 9 2014 usr/share/terminfo/6c/linux-koi8
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/73/._screen-16color
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1990 Sep 9 2014 usr/share/terminfo/73/screen-16color
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/73/._screen2
<span class="nt">-rw-r--r--</span> 0 morpheus staff 585 Sep 9 2014 usr/share/terminfo/73/screen2
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/73/._screen3
<span class="nt">-rw-r--r--</span> 0 morpheus staff 630 Sep 9 2014 usr/share/terminfo/73/screen3
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/73/._screen-16color-bce-s
<span class="nt">-rw-r--r--</span> 0 morpheus staff 2030 Sep 9 2014 usr/share/terminfo/73/screen-16color-bce-s
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/73/._screen-256color-bce
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1840 Sep 9 2014 usr/share/terminfo/73/screen-256color-bce
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/73/._screen.rxvt
<span class="nt">-rw-r--r--</span> 0 morpheus staff 2082 Sep 9 2014 usr/share/terminfo/73/screen.rxvt
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/73/._screen.xterm-r6
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1503 Sep 9 2014 usr/share/terminfo/73/screen.xterm-r6
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/73/._screen-w
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1566 Sep 9 2014 usr/share/terminfo/73/screen-w
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/73/._screen.xterm-xfree86
<span class="nt">-rw-r--r--</span> 0 morpheus staff 3263 Sep 9 2014 usr/share/terminfo/73/screen.xterm-xfree86
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/73/._screen-16color-s
<span class="nt">-rw-r--r--</span> 0 morpheus staff 2020 Sep 9 2014 usr/share/terminfo/73/screen-16color-s
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/73/._screen.linux
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1710 Sep 9 2014 usr/share/terminfo/73/screen.linux
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/73/._screen-256color-bce-s
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1866 Sep 9 2014 usr/share/terminfo/73/screen-256color-bce-s
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/73/._screen
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1550 Sep 9 2014 usr/share/terminfo/73/screen
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/73/._screen-bce
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1562 Sep 9 2014 usr/share/terminfo/73/screen-bce
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/73/._screen-256color-s
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1856 Sep 9 2014 usr/share/terminfo/73/screen-256color-s
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/73/._screen.mlterm
<span class="nt">-rw-r--r--</span> 0 morpheus staff 2590 Sep 9 2014 usr/share/terminfo/73/screen.mlterm
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/73/._screen-s
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1584 Sep 9 2014 usr/share/terminfo/73/screen-s
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/73/._screen.teraterm
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1548 Sep 9 2014 usr/share/terminfo/73/screen.teraterm
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/73/._screen-16color-bce
<span class="nt">-rw-r--r--</span> 0 morpheus staff 2002 Sep 9 2014 usr/share/terminfo/73/screen-16color-bce
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/73/._screen.xterm-new
<span class="nt">-rw-r--r--</span> 0 morpheus staff 3263 Sep 9 2014 usr/share/terminfo/73/screen.xterm-new
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/73/._screen-256color
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1828 Sep 9 2014 usr/share/terminfo/73/screen-256color
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/73/._screen+fkeys
<span class="nt">-rw-r--r--</span> 0 morpheus staff 474 Sep 9 2014 usr/share/terminfo/73/screen+fkeys
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/61/._ansi80x50-mono
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1264 Sep 9 2014 usr/share/terminfo/61/ansi80x50-mono
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/61/._ansi+idl1
<span class="nt">-rw-r--r--</span> 0 morpheus staff 138 Sep 9 2014 usr/share/terminfo/61/ansi+idl1
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/61/._ansil
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1502 Sep 9 2014 usr/share/terminfo/61/ansil
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/61/._ansi+idc
<span class="nt">-rw-r--r--</span> 0 morpheus staff 263 Sep 9 2014 usr/share/terminfo/61/ansi+idc
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/61/._ansiw
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1459 Sep 9 2014 usr/share/terminfo/61/ansiw
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/61/._ansi80x30
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1496 Sep 9 2014 usr/share/terminfo/61/ansi80x30
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/61/._ansi-mono
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1370 Sep 9 2014 usr/share/terminfo/61/ansi-mono
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/61/._ansi+pp
<span class="nt">-rw-r--r--</span> 0 morpheus staff 295 Sep 9 2014 usr/share/terminfo/61/ansi+pp
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/61/._ansi+idl
<span class="nt">-rw-r--r--</span> 0 morpheus staff 270 Sep 9 2014 usr/share/terminfo/61/ansi+idl
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/61/._ansil-mono
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1264 Sep 9 2014 usr/share/terminfo/61/ansil-mono
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/61/._ansi80x30-mono
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1252 Sep 9 2014 usr/share/terminfo/61/ansi80x30-mono
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/61/._ansi80x25-raw
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1459 Sep 9 2014 usr/share/terminfo/61/ansi80x25-raw
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/61/._ansi+csr
<span class="nt">-rw-r--r--</span> 0 morpheus staff 349 Sep 9 2014 usr/share/terminfo/61/ansi+csr
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/61/._ansi-generic
<span class="nt">-rw-r--r--</span> 0 morpheus staff 733 Sep 9 2014 usr/share/terminfo/61/ansi-generic
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/61/._ansi+sgr
<span class="nt">-rw-r--r--</span> 0 morpheus staff 368 Sep 9 2014 usr/share/terminfo/61/ansi+sgr
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/61/._ansi+cup
<span class="nt">-rw-r--r--</span> 0 morpheus staff 69 Sep 9 2014 usr/share/terminfo/61/ansi+cup
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/61/._ansi-emx
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1582 Sep 9 2014 usr/share/terminfo/61/ansi-emx
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/61/._ansi+sgrbold
<span class="nt">-rw-r--r--</span> 0 morpheus staff 463 Sep 9 2014 usr/share/terminfo/61/ansi+sgrbold
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/61/._ansi+sgrul
<span class="nt">-rw-r--r--</span> 0 morpheus staff 143 Sep 9 2014 usr/share/terminfo/61/ansi+sgrul
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/61/._ansi80x60-mono
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1252 Sep 9 2014 usr/share/terminfo/61/ansi80x60-mono
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/61/._ansi+sgrso
<span class="nt">-rw-r--r--</span> 0 morpheus staff 139 Sep 9 2014 usr/share/terminfo/61/ansi+sgrso
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/61/._ansi
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1481 Sep 9 2014 usr/share/terminfo/61/ansi
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/61/._ansi-color-2-emx
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1580 Sep 9 2014 usr/share/terminfo/61/ansi-color-2-emx
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/61/._ansis-mono
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1478 Sep 9 2014 usr/share/terminfo/61/ansis-mono
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/61/._ansi-color-3-emx
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1577 Sep 9 2014 usr/share/terminfo/61/ansi-color-3-emx
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/61/._ansisysk
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1518 Sep 9 2014 usr/share/terminfo/61/ansisysk
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/61/._ansi43m
<span class="nt">-rw-r--r--</span> 0 morpheus staff 735 Sep 9 2014 usr/share/terminfo/61/ansi43m
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/61/._ansi-mtabs
<span class="nt">-rw-r--r--</span> 0 morpheus staff 444 Sep 9 2014 usr/share/terminfo/61/ansi-mtabs
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/61/._ansi+sgrdim
<span class="nt">-rw-r--r--</span> 0 morpheus staff 463 Sep 9 2014 usr/share/terminfo/61/ansi+sgrdim
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/61/._ansi80x25
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1502 Sep 9 2014 usr/share/terminfo/61/ansi80x25
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/61/._ansi+erase
<span class="nt">-rw-r--r--</span> 0 morpheus staff 55 Sep 9 2014 usr/share/terminfo/61/ansi+erase
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/61/._ansi+rep
<span class="nt">-rw-r--r--</span> 0 morpheus staff 286 Sep 9 2014 usr/share/terminfo/61/ansi+rep
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/61/._ansis
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1502 Sep 9 2014 usr/share/terminfo/61/ansis
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/61/._ansi80x50
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1502 Sep 9 2014 usr/share/terminfo/61/ansi80x50
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/61/._ansi+tabs
<span class="nt">-rw-r--r--</span> 0 morpheus staff 306 Sep 9 2014 usr/share/terminfo/61/ansi+tabs
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/61/._ansi+local1
<span class="nt">-rw-r--r--</span> 0 morpheus staff 80 Sep 9 2014 usr/share/terminfo/61/ansi+local1
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/61/._ansi80x60
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1496 Sep 9 2014 usr/share/terminfo/61/ansi80x60
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/61/._ansi+rca
<span class="nt">-rw-r--r--</span> 0 morpheus staff 308 Sep 9 2014 usr/share/terminfo/61/ansi+rca
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/61/._ansi-mini
<span class="nt">-rw-r--r--</span> 0 morpheus staff 418 Sep 9 2014 usr/share/terminfo/61/ansi-mini
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/61/._ansi+enq
<span class="nt">-rw-r--r--</span> 0 morpheus staff 685 Sep 9 2014 usr/share/terminfo/61/ansi+enq
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/61/._ansi-nt
<span class="nt">-rw-r--r--</span> 0 morpheus staff 476 Sep 9 2014 usr/share/terminfo/61/ansi-nt
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/61/._ansi77
<span class="nt">-rw-r--r--</span> 0 morpheus staff 543 Sep 9 2014 usr/share/terminfo/61/ansi77
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/61/._ansi-mr
<span class="nt">-rw-r--r--</span> 0 morpheus staff 377 Sep 9 2014 usr/share/terminfo/61/ansi-mr
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/61/._ansi80x43-mono
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1252 Sep 9 2014 usr/share/terminfo/61/ansi80x43-mono
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/61/._ansi.sys
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1257 Sep 9 2014 usr/share/terminfo/61/ansi.sys
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/61/._ansi.sys-old
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1255 Sep 9 2014 usr/share/terminfo/61/ansi.sys-old
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/61/._ansi.sysk
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1518 Sep 9 2014 usr/share/terminfo/61/ansi.sysk
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/61/._ansi80x25-mono
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1478 Sep 9 2014 usr/share/terminfo/61/ansi80x25-mono
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/61/._ansi+inittabs
<span class="nt">-rw-r--r--</span> 0 morpheus staff 314 Sep 9 2014 usr/share/terminfo/61/ansi+inittabs
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/61/._ansi+local
<span class="nt">-rw-r--r--</span> 0 morpheus staff 306 Sep 9 2014 usr/share/terminfo/61/ansi+local
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/61/._ansi-m
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1370 Sep 9 2014 usr/share/terminfo/61/ansi-m
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/61/._ansi80x43
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1496 Sep 9 2014 usr/share/terminfo/61/ansi80x43
<span class="nt">-rw-r--r--</span> 0 morpheus staff 178 Sep 9 2014 usr/share/terminfo/61/._ansi+arrows
<span class="nt">-rw-r--r--</span> 0 morpheus staff 222 Sep 9 2014 usr/share/terminfo/61/ansi+arrows
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 19:23 usr/local/._bin
drwxr-xr-x 0 morpheus staff 0 Apr 25 19:23 usr/local/bin/
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Mar 18 2018 usr/local/._lib
drwxr-xr-x 0 morpheus staff 0 Mar 18 2018 usr/local/lib/
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Mar 18 2018 usr/local/lib/._zsh
drwxr-xr-x 0 morpheus staff 0 Mar 18 2018 usr/local/lib/zsh/
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Mar 18 2018 usr/local/lib/zsh/._5.0.8
drwxr-xr-x 0 morpheus staff 0 Mar 18 2018 usr/local/lib/zsh/5.0.8/
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Mar 18 2018 usr/local/lib/zsh/5.0.8/._zsh
drwxr-xr-x 0 morpheus staff 0 Mar 18 2018 usr/local/lib/zsh/5.0.8/zsh/
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/._termcap.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 51968 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/termcap.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/._zleparameter.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 51424 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/zleparameter.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/._example.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 51728 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/example.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/._tcp.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 52832 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/tcp.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/._newuser.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 50992 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/newuser.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/._deltochar.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 51296 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/deltochar.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/._complete.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 157488 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/complete.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/._mapfile.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 51936 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/mapfile.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/._stat.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 52224 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/stat.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/._compctl.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 94992 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/compctl.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/._zselect.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 51936 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/zselect.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/._parameter.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 72032 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/parameter.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/._datetime.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 52320 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/datetime.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/._socket.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 51696 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/socket.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/._terminfo.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 51968 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/terminfo.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/._clone.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 51792 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/clone.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/._regex.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 51776 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/regex.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/._attr.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 51488 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/attr.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/._curses.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 56272 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/curses.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/._files.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 53360 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/files.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/._system.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 53056 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/system.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/._zpty.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 54592 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/zpty.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/._zle.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 284896 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/zle.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/._mathfunc.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 53200 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/mathfunc.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/._zutil.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 54880 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/zutil.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/._complist.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 92064 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/complist.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/._zftp.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 73568 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/zftp.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/._cap.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 50736 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/cap.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/._computil.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 89472 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/computil.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/._zprof.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 51312 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/zprof.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/._langinfo.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 50992 Dec 20 2017 usr/local/lib/zsh/5.0.8/zsh/langinfo.so
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Dec 20 2017 usr/local/bin/._wget
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 737808 Dec 20 2017 usr/local/bin/wget
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Dec 20 2017 usr/local/bin/._dbclient
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 234688 Dec 20 2017 usr/local/bin/dbclient
<span class="nt">-rw-r--r--</span> 0 morpheus staff 166576 Apr 25 19:23 usr/local/bin/qilin.o
<span class="nt">-rw-r--r--</span> 0 morpheus staff 1060 Apr 25 19:23 usr/local/bin/shaihulud.c
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Dec 20 2017 usr/local/bin/._filemon
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 52304 Dec 20 2017 usr/local/bin/filemon
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Dec 20 2017 usr/local/bin/._dropbear
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 235696 Dec 20 2017 usr/local/bin/dropbear
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 194480 Apr 25 19:23 usr/local/bin/shaihulud
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 590944 Apr 25 17:48 usr/local/bin/procexp
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 552544 Apr 25 17:50 usr/local/bin/jtool
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Dec 20 2017 usr/local/bin/._dropbearkey
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 169408 Dec 20 2017 usr/local/bin/dropbearkey
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 70592 Feb 28 2018 usr/local/bin/jlutil
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 504928 Apr 25 18:03 usr/local/bin/joker
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Dec 20 2017 usr/local/bin/._dropbearconvert
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 170144 Dec 20 2017 usr/local/bin/dropbearconvert
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Dec 20 2017 usr/local/bin/._dropbear.orig
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 252400 Dec 20 2017 usr/local/bin/dropbear.orig
<span class="nt">-rw-r--r--</span> 0 morpheus staff 910 Apr 25 17:48 usr/local/bin/procexp.ent
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:45 usr/sbin/._joreg
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 75296 Apr 25 17:45 usr/sbin/joreg
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:45 usr/sbin/._ioreg
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 75296 Apr 25 17:45 usr/sbin/ioreg
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:45 usr/sbin/._sysctl
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 53088 Apr 25 17:45 usr/sbin/sysctl
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:45 usr/sbin/._taskpolicy
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 51824 Apr 25 17:45 usr/sbin/taskpolicy
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:45 usr/sbin/._netstat
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 227472 Apr 25 17:45 usr/sbin/netstat
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:45 usr/sbin/._ltop
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 52384 Apr 25 17:45 usr/sbin/ltop
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:45 usr/sbin/._chown
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 52192 Apr 25 17:45 usr/sbin/chown
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:53 usr/sbin/._kextstat
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 77024 Apr 25 17:53 usr/sbin/kextstat
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:46 usr/bin/._tee
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 51120 Apr 25 17:46 usr/bin/tee
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:46 usr/bin/._split
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 68880 Apr 25 17:46 usr/bin/split
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:46 usr/bin/._vim
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 2190272 Apr 25 17:46 usr/bin/vim
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:46 usr/bin/._hexdump
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 71488 Apr 25 17:46 usr/bin/hexdump
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:52 usr/bin/._lsmp
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 71380 Apr 25 17:52 usr/bin/lsmp
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:46 usr/bin/._vm_stat
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 52064 Apr 25 17:46 usr/bin/vm_stat
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:46 usr/bin/._syslog
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 187472 Apr 25 17:46 usr/bin/syslog
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:46 usr/bin/._du
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 53088 Apr 25 17:46 usr/bin/du
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:46 usr/bin/._fs_usage
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 125344 Apr 25 17:46 usr/bin/fs_usage
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:46 usr/bin/._renice
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 51008 Apr 25 17:46 usr/bin/renice
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:46 usr/bin/._xxd
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 52016 Apr 25 17:46 usr/bin/xxd
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:46 usr/bin/._sc_usage
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 73968 Apr 25 17:46 usr/bin/sc_usage
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:46 usr/bin/._less
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 233968 Apr 25 17:46 usr/bin/less
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:46 usr/bin/._sed
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 73184 Apr 25 17:46 usr/bin/sed
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:46 usr/bin/._nano
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 262992 Apr 25 17:46 usr/bin/nano
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:46 usr/bin/._tset
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 54400 Apr 25 17:46 usr/bin/tset
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:46 usr/bin/._seq
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 51904 Apr 25 17:46 usr/bin/seq
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:46 usr/bin/._uname
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 51104 Apr 25 17:46 usr/bin/uname
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:46 usr/bin/._uicache
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 53520 Apr 25 17:46 usr/bin/uicache
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:46 usr/bin/._reset
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 54400 Apr 25 17:46 usr/bin/reset
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:46 usr/bin/._wc
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 51840 Apr 25 17:46 usr/bin/wc
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:46 usr/bin/._gzip
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 90000 Apr 25 17:46 usr/bin/gzip
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:46 usr/bin/._printf
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 51968 Apr 25 17:46 usr/bin/printf
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:46 usr/bin/._tail
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 53872 Apr 25 17:46 usr/bin/tail
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:46 usr/bin/._grep
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 190768 Apr 25 17:46 usr/bin/grep
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:46 usr/bin/._script
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 53232 Apr 25 17:46 usr/bin/script
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:46 usr/bin/._more
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 233968 Apr 25 17:46 usr/bin/more
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:46 usr/bin/._time
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 51136 Apr 25 17:46 usr/bin/time
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:46 usr/bin/._plconvert
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 52080 Apr 25 17:46 usr/bin/plconvert
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:46 usr/bin/._head
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 51776 Apr 25 17:46 usr/bin/head
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:46 usr/bin/._clear
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 50640 Apr 25 17:46 usr/bin/clear
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:46 usr/bin/._killall
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 52496 Apr 25 17:46 usr/bin/killall
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:46 usr/bin/._stat
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 52080 Apr 25 17:46 usr/bin/stat
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:46 usr/bin/._sqlite3
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 1333456 Apr 25 17:46 usr/bin/sqlite3
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:46 usr/bin/._screen
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 428416 Apr 25 17:46 usr/bin/screen
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:46 usr/bin/._arch
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 54976 Apr 25 17:46 usr/bin/arch
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:46 usr/bin/._cut
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 53040 Apr 25 17:46 usr/bin/cut
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:46 usr/bin/._xargs
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 53568 Apr 25 17:46 usr/bin/xargs
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:46 usr/bin/._what
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 50816 Apr 25 17:46 usr/bin/what
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:46 usr/bin/._chflags
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 51296 Apr 25 17:46 usr/bin/chflags
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:46 usr/bin/._id
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 51936 Apr 25 17:46 usr/bin/id
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:46 usr/bin/._find
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 94368 Apr 25 17:46 usr/bin/find
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:46 usr/bin/._scp
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 55552 Apr 25 17:46 usr/bin/scp
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:46 usr/bin/._true
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 50416 Apr 25 17:46 usr/bin/true
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:46 usr/bin/._hostinfo
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 51216 Apr 25 17:46 usr/bin/hostinfo
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:46 usr/bin/._tar
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 459392 Apr 25 17:46 usr/bin/tar
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:46 usr/bin/._false
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 50416 Apr 25 17:46 usr/bin/false
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 55648 Apr 25 17:46 usr/bin/login
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:46 usr/bin/._which
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 51504 Apr 25 17:46 usr/bin/which
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:46 usr/bin/._passwd
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 52832 Apr 25 17:46 usr/bin/passwd
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:46 usr/bin/._nohup
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 51312 Apr 25 17:46 usr/bin/nohup
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 53184 Apr 25 17:46 usr/bin/w
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 178 Apr 25 17:46 usr/bin/._gunzip
<span class="nt">-rwxr-xr-x</span> 0 morpheus staff 90000 Apr 25 17:46 usr/bin/gunzip
Saigon:~ geosn0w<span class="nv">$ </span>
</code></pre></div></div>
<h3 id="remounting-the-file-system">Remounting the File System</h3>
<p>So, we exploited the kernel and got kernel memory R/W, we exploited a bug or we bestowed ourselves the kernel credentials so we also exited the SandBox, now we wanna drop our payload (which can contain Cydia, binaries, config files, dummy files for checking whether the jailbreak was installed, etc). To be able to do that, we need to have Write permissions over the file system. By default, the iOS ROOT FS is mounted as Read Only, so we will need to remount that, hence the name of the patch: Root FS Remount.</p>
<p>This is the component that was missing back in July 2018 when Electra for iOS 11.3.1 was in development, and most of the eta folks went haywire.</p>
<p>So, how do we do that?</p>
<p>On QiLin (and therefore on LiberiOS and Osiris Jailbreak), the remounting up to iOS 11.2.6 works this way:
As I said, by default the ROOT FS is mounted as read-only. Not only that, but the SandBox also has a hook that prevents you from remounting it as Read / Write. The hook is enforced through MACF calls in <code class="high">mount_begin_update()</code> and <code class="high">mount_common()</code>. All the hook does it to check for the presence of the <code class="high">MNT_ROOTFS</code> flag in the mount flags. If it exists, the operation fails. So what QiLin does? Simple. It turns off the <code class="high">MNT_ROOTFS</code> flag.</p>
<p>The following listing is the <code class="high">remountRootFS</code> in the QiLin Toolkit and was made publicly available by Jonathan Levin on newosxbook.com and in the Volume III of *OS Internals.</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="nf">remountRootFS</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span>
<span class="p">{</span>
<span class="p">...</span>
<span class="kt">uint64_t</span> <span class="n">rootVnodeAddr</span> <span class="o">=</span> <span class="n">findKernelSymbol</span><span class="p">(</span><span class="s">"_rootvnode"</span><span class="p">);</span>
<span class="kt">uint64_t</span> <span class="o">*</span><span class="n">actualVnodeAddr</span><span class="p">;</span>
<span class="k">struct</span> <span class="n">vnode</span> <span class="o">*</span><span class="n">rootvnode</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="kt">char</span> <span class="o">*</span><span class="n">v_mount</span><span class="p">;</span>
<span class="n">status</span><span class="p">(</span><span class="s">"Attempting to remount rootFS...</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="n">readKernelMemory</span><span class="p">(</span><span class="n">rootVnodeAddr</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="p">),</span> <span class="o">&</span><span class="n">actualVnodeAddr</span><span class="p">);</span>
<span class="n">readKernelMemory</span><span class="p">(</span><span class="o">*</span><span class="n">actualVnodeAddr</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="k">struct</span> <span class="n">vnode</span><span class="p">),</span> <span class="o">&</span><span class="n">rootvnode</span><span class="p">);</span>
<span class="n">readKernelMemory</span><span class="p">(</span><span class="n">rootvnode</span><span class="o">-></span><span class="n">v_mount</span><span class="p">,</span> <span class="mh">0x100</span><span class="p">,</span> <span class="o">&</span><span class="n">v_mount</span><span class="p">);</span>
<span class="c1">// Disable MNT_ROOTFS momentarily, remounts , and then flips the flag back</span>
<span class="kt">uint32_t</span> <span class="n">mountFlags</span> <span class="o">=</span> <span class="p">(</span><span class="o">*</span><span class="p">(</span><span class="kt">uint32_t</span> <span class="o">*</span> <span class="p">)(</span><span class="n">v_mount</span> <span class="o">+</span> <span class="mh">0x70</span><span class="p">))</span> <span class="o">&</span> <span class="o">~</span><span class="p">(</span><span class="n">MNT_ROOTFS</span> <span class="o">|</span> <span class="n">MNT_RDONLY</span><span class="p">);</span>
<span class="n">writeKernelMemory</span><span class="p">(((</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="n">rootvnode</span><span class="o">-></span><span class="n">v_mount</span><span class="p">)</span> <span class="o">+</span> <span class="mh">0x70</span> <span class="p">,</span><span class="k">sizeof</span><span class="p">(</span><span class="n">mountFlags</span><span class="p">),</span> <span class="o">&</span><span class="n">mountFlags</span><span class="p">);</span>
<span class="kt">char</span> <span class="o">*</span><span class="n">opts</span> <span class="o">=</span> <span class="n">strdup</span><span class="p">(</span><span class="s">"/dev/disk0s1s1"</span><span class="p">);</span>
<span class="c1">// Not enough to just change the MNT_RDONLY flag - we have to call</span>
<span class="c1">// mount(2) again, to refresh the kernel code paths for mounting..</span>
<span class="kt">int</span> <span class="n">rc</span> <span class="o">=</span> <span class="n">mount</span><span class="p">(</span><span class="s">"apfs"</span><span class="p">,</span> <span class="s">"/"</span><span class="p">,</span> <span class="n">MNT_UPDATE</span><span class="p">,</span> <span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="p">)</span><span class="o">&</span><span class="n">opts</span><span class="p">);</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"RC: %d (flags: 0x%x) %s </span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">rc</span><span class="p">,</span> <span class="n">mountFlags</span><span class="p">,</span> <span class="n">strerror</span><span class="p">(</span><span class="n">errno</span><span class="p">));</span>
<span class="n">mountFlags</span> <span class="o">|=</span> <span class="n">MNT_ROOTFS</span><span class="p">;</span>
<span class="n">writeKernelMemory</span><span class="p">(((</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="n">rootvnode</span><span class="o">-></span><span class="n">v_mount</span><span class="p">)</span> <span class="o">+</span> <span class="mh">0x70</span> <span class="p">,</span><span class="k">sizeof</span><span class="p">(</span><span class="n">mountFlags</span><span class="p">),</span> <span class="o">&</span><span class="n">mountFlags</span><span class="p">);</span>
<span class="c1">// Quick test:</span>
<span class="kt">int</span> <span class="n">fd</span> <span class="o">=</span> <span class="n">open</span> <span class="p">(</span><span class="s">"/test.txt"</span><span class="p">,</span> <span class="n">O_TRUNC</span><span class="o">|</span> <span class="n">O_CREAT</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">fd</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span> <span class="n">error</span> <span class="p">(</span><span class="s">"Failed to remount /"</span><span class="p">);</span> <span class="p">}</span>
<span class="k">else</span> <span class="p">{</span>
<span class="n">status</span><span class="p">(</span><span class="s">"Mounted / as read write :-)</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="n">unlink</span><span class="p">(</span><span class="s">"/test.txt"</span><span class="p">);</span> <span class="c1">// clean up</span>
<span class="p">}</span>
<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</code></pre></div></div>
<p>Jonathan Levin’s code is pretty straightforward. Flip the <code class="high">MNT_ROOTFS</code> flag, call <code class="high">mount(2)</code> to refresh the kernel code paths for mounting, restore the flag and test. Done. You’re R/W.</p>
<p>On older jailbreaks patches to <code class="high">LightweightVolumeManager::_mapForIO</code> were done.</p>
<h3 id="electras-remount">Electra’s remount</h3>
<p>iOS 11.3 took it a step further by involving APFS Snapshots. APFS has been used for quite a long time in iOS at the moment when Apple started using the snapshots, but when they did it broke the tried and true remount we had for iOS 11.2.x and even older. To fix this, a new bug needed to be found. The problem is that iOS would revert to a snapshot which is mounted read-only, so everything we install in terms of tweaks, binaries, etc is gone every time we reboot.</p>
<p>At this point two things can be done: Change the whole jailbreaking and go “ROOTless”, or find a way around the snapshots.
It is thanks to @pwn20wnd and @umanghere that a proper remount has been created. Umang has found a “bug” that pwn20wnd has exploited in Electra.</p>
<p>Well, to say that it was a bug it’s a bit of a stretch. It isn’t a bug but rather a feature of <code class="high">fs_snapshot syscall</code>. Anyways, it works.</p>
<p>Pwn20wnd’s bypass for this snapshot problem is also a very straightforward one.
Here is the function from the source code of Electra for iOS 11.3.1:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="nf">remountRootAsRW</span><span class="p">(</span><span class="kt">uint64_t</span> <span class="n">slide</span><span class="p">,</span> <span class="kt">uint64_t</span> <span class="n">kern_proc</span><span class="p">,</span> <span class="kt">uint64_t</span> <span class="n">our_proc</span><span class="p">,</span> <span class="kt">int</span> <span class="n">snapshot_success</span><span class="p">){</span>
<span class="k">if</span> <span class="p">(</span><span class="cm">/* iOS 11.2.6 or lower don't need snapshot */</span> <span class="n">kCFCoreFoundationVersionNumber</span> <span class="o"><=</span> <span class="mi">1451</span><span class="p">.</span><span class="mi">51</span> <span class="o">||</span> <span class="cm">/* we're already remounted properly */</span> <span class="n">snapshot_success</span> <span class="o">==</span> <span class="mi">0</span><span class="p">){</span>
<span class="k">return</span> <span class="n">remountRootAsRW_old</span><span class="p">(</span><span class="n">slide</span><span class="p">,</span> <span class="n">kern_proc</span><span class="p">,</span> <span class="n">our_proc</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">getOffsets</span><span class="p">(</span><span class="n">slide</span><span class="p">)){</span>
<span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">uint64_t</span> <span class="n">kernucred</span> <span class="o">=</span> <span class="n">rk64</span><span class="p">(</span><span class="n">kern_proc</span><span class="o">+</span><span class="n">offsetof_p_ucred</span><span class="p">);</span>
<span class="kt">uint64_t</span> <span class="n">ourucred</span> <span class="o">=</span> <span class="n">rk64</span><span class="p">(</span><span class="n">our_proc</span><span class="o">+</span><span class="n">offsetof_p_ucred</span><span class="p">);</span>
<span class="kt">uint64_t</span> <span class="n">vfs_context</span> <span class="o">=</span> <span class="n">get_vfs_context</span><span class="p">();</span>
<span class="kt">char</span> <span class="o">*</span><span class="n">dev_path</span> <span class="o">=</span> <span class="s">"/dev/disk0s1s1"</span><span class="p">;</span>
<span class="kt">uint64_t</span> <span class="n">devVnode</span> <span class="o">=</span> <span class="n">getVnodeAtPath</span><span class="p">(</span><span class="n">vfs_context</span><span class="p">,</span> <span class="n">dev_path</span><span class="p">);</span>
<span class="kt">uint64_t</span> <span class="n">specInfo</span> <span class="o">=</span> <span class="n">rk64</span><span class="p">(</span><span class="n">devVnode</span> <span class="o">+</span> <span class="n">offsetof_v_specinfo</span><span class="p">);</span>
<span class="n">wk32</span><span class="p">(</span><span class="n">specInfo</span> <span class="o">+</span> <span class="n">offsetof_si_flags</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> <span class="c1">//clear dev vnode's v_specflags</span>
<span class="k">if</span> <span class="p">(</span><span class="n">file_exists</span><span class="p">(</span><span class="n">ROOTFSMNT</span><span class="p">))</span>
<span class="n">rmdir</span><span class="p">(</span><span class="n">ROOTFSMNT</span><span class="p">);</span>
<span class="n">mkdir</span><span class="p">(</span><span class="n">ROOTFSMNT</span><span class="p">,</span> <span class="mo">0755</span><span class="p">);</span>
<span class="n">chown</span><span class="p">(</span><span class="n">ROOTFSMNT</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"Temporarily setting kern ucred</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="n">wk64</span><span class="p">(</span><span class="n">our_proc</span><span class="o">+</span><span class="n">offsetof_p_ucred</span><span class="p">,</span> <span class="n">kernucred</span><span class="p">);</span>
<span class="kt">int</span> <span class="n">rv</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="n">mountDevAsRWAtPath</span><span class="p">(</span><span class="n">dev_path</span><span class="p">,</span> <span class="n">ROOTFSMNT</span><span class="p">)</span> <span class="o">!=</span> <span class="n">ERR_SUCCESS</span><span class="p">)</span> <span class="p">{</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"Error mounting root at %s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">ROOTFSMNT</span><span class="p">);</span>
<span class="k">goto</span> <span class="n">out</span><span class="p">;</span>
<span class="p">}</span>
<span class="cm">/* APFS snapshot mitigation bypass bug by CoolStar, exploitation by Pwn20wnd */</span>
<span class="cm">/* Disables the new APFS snapshot mitigations introduced in iOS 11.3 */</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"Disabling the APFS snapshot mitigations</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">systemSnapshot</span> <span class="o">=</span> <span class="n">find_system_snapshot</span><span class="p">(</span><span class="n">ROOTFSMNT</span><span class="p">);</span>
<span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">newSystemSnapshot</span> <span class="o">=</span> <span class="s">"orig-fs"</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">systemSnapshot</span><span class="p">)</span> <span class="p">{</span>
<span class="k">goto</span> <span class="n">out</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">int</span> <span class="n">rvrename</span> <span class="o">=</span> <span class="n">do_rename</span><span class="p">(</span><span class="n">ROOTFSMNT</span><span class="p">,</span> <span class="n">systemSnapshot</span><span class="p">,</span> <span class="n">newSystemSnapshot</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">rvrename</span><span class="p">)</span> <span class="p">{</span>
<span class="k">goto</span> <span class="n">out</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">rv</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="n">unmount</span><span class="p">(</span><span class="n">ROOTFSMNT</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
<span class="n">rmdir</span><span class="p">(</span><span class="n">ROOTFSMNT</span><span class="p">);</span>
<span class="nl">out:</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"Restoring our ucred</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="n">wk64</span><span class="p">(</span><span class="n">our_proc</span><span class="o">+</span><span class="n">offsetof_p_ucred</span><span class="p">,</span> <span class="n">ourucred</span><span class="p">);</span>
<span class="c1">//cleanup</span>
<span class="n">vnode_put</span><span class="p">(</span><span class="n">devVnode</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">rv</span><span class="p">)</span> <span class="p">{</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"Disabled the APFS snapshot mitigations</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"Restarting</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="n">restarting</span><span class="p">();</span>
<span class="n">sleep</span><span class="p">(</span><span class="mi">2</span><span class="p">);</span>
<span class="n">do_restart</span><span class="p">();</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"Failed to disable the APFS snapshot mitigations</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>It may look complicated. That’s because it is. It took Pwn20wnd a lot of work to achieve this bypass, but once the bug was known, the problem started to fall apart. See, the bug is very simple: iOS will revert to an APFS System snapshot after every reboot if there is one. Here’s the catch - if there is one. If there isn’t, instead of boot looping or erroring out in a destructive way, iOS casually continues booting just like it did on iOS 11.2.6 where there was no snapshot.</p>
<p>So the patch? Find and rename the snapshot to something else.</p>
<p>The implementation? A bit more complicated.
If you analyze the code you can see that the name of the said snapshot is dynamic (or at least contains a dynamic part) so it cannot be hardcoded. The dynamic part happens to be the <code class="high">boot-manifest-hash</code>. Before doing anything, Pwn20wnd seems to be bestowing himself the kernel credentials.</p>
<p>You can find it yourself by running:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ioreg <span class="nt">-p</span> IODeviceTree <span class="nt">-l</span> | <span class="nb">grep </span>boot-manifest-hash
</code></pre></div></div>
<p>In the Electra, all the logic for finding the boot-manifest-hash is located in <code class="high">apfs_util.c</code> as you can see here:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">char</span> <span class="o">*</span><span class="nf">copyBootHash</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="p">{</span>
<span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">buf</span><span class="p">[</span><span class="mi">1024</span><span class="p">];</span>
<span class="kt">uint32_t</span> <span class="n">length</span> <span class="o">=</span> <span class="mi">1024</span><span class="p">;</span>
<span class="n">io_registry_entry_t</span> <span class="n">chosen</span> <span class="o">=</span> <span class="n">IORegistryEntryFromPath</span><span class="p">(</span><span class="n">kIOMasterPortDefault</span><span class="p">,</span> <span class="s">"IODeviceTree:/chosen"</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">MACH_PORT_VALID</span><span class="p">(</span><span class="n">chosen</span><span class="p">))</span> <span class="p">{</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"Unable to get IODeviceTree:/chosen port</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">kern_return_t</span> <span class="n">ret</span> <span class="o">=</span> <span class="n">IORegistryEntryGetProperty</span><span class="p">(</span><span class="n">chosen</span><span class="p">,</span> <span class="s">"boot-manifest-hash"</span><span class="p">,</span> <span class="p">(</span><span class="kt">void</span><span class="o">*</span><span class="p">)</span><span class="n">buf</span><span class="p">,</span> <span class="o">&</span><span class="n">length</span><span class="p">);</span>
<span class="n">IOObjectRelease</span><span class="p">(</span><span class="n">chosen</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">ret</span> <span class="o">!=</span> <span class="n">ERR_SUCCESS</span><span class="p">)</span> <span class="p">{</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"Unable to read boot-manifest-hash</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span>
<span class="p">}</span>
<span class="c1">// Make a hex string out of the hash</span>
<span class="kt">char</span> <span class="n">manifestHash</span><span class="p">[</span><span class="n">length</span><span class="o">*</span><span class="mi">2</span><span class="o">+</span><span class="mi">1</span><span class="p">];</span>
<span class="n">bzero</span><span class="p">(</span><span class="n">manifestHash</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">manifestHash</span><span class="p">));</span>
<span class="kt">int</span> <span class="n">i</span><span class="p">;</span>
<span class="k">for</span> <span class="p">(</span><span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o"><</span><span class="n">length</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
<span class="n">sprintf</span><span class="p">(</span><span class="n">manifestHash</span><span class="o">+</span><span class="n">i</span><span class="o">*</span><span class="mi">2</span><span class="p">,</span> <span class="s">"%02X"</span><span class="p">,</span> <span class="n">buf</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
<span class="p">}</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"Hash: %s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">manifestHash</span><span class="p">);</span>
<span class="k">return</span> <span class="n">strdup</span><span class="p">(</span><span class="n">manifestHash</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>
<p>This function is called from inside another function called <code class="high">find_system_snapshot</code> which handles the logic for finding the snapshot itself. The function appends the retrieved manifestHash to the hard-coded part which is <code class="high">com.apple.os.update-</code> resulting in the real name of the current snapshot. It then returns the snapshot name to the caller, but not before printing it out loud :P</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="nf">find_system_snapshot</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">rootfsmnt</span><span class="p">)</span> <span class="p">{</span>
<span class="kt">char</span> <span class="o">*</span><span class="n">bootHash</span> <span class="o">=</span> <span class="n">copyBootHash</span><span class="p">();</span>
<span class="kt">char</span> <span class="o">*</span><span class="n">system_snapshot</span> <span class="o">=</span> <span class="n">malloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span> <span class="o">+</span> <span class="p">(</span><span class="mi">21</span> <span class="o">+</span> <span class="n">strlen</span><span class="p">(</span><span class="n">bootHash</span><span class="p">)));</span>
<span class="n">bzero</span><span class="p">(</span><span class="n">system_snapshot</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span> <span class="o">+</span> <span class="p">(</span><span class="mi">21</span> <span class="o">+</span> <span class="n">strlen</span><span class="p">(</span><span class="n">bootHash</span><span class="p">)));</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">bootHash</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">sprintf</span><span class="p">(</span><span class="n">system_snapshot</span><span class="p">,</span> <span class="s">"com.apple.os.update-%s"</span><span class="p">,</span> <span class="n">bootHash</span><span class="p">);</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"System snapshot: %s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">system_snapshot</span><span class="p">);</span>
<span class="k">return</span> <span class="n">system_snapshot</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>With kernel’s credentials in place, and with the proper name of the snapshot, Pwn20wnd returns back into rootfs_remount.c for the last part of this magnificent exploit - renaming the Snapshot. He renames it to “orig-fs”, then he checks if the renaming succeeded. Then he restores his own credentials and drops kernel’s. Finally, he reboots the device. That’s why the first time you use Electra for iOS 11.3-11.3.1 your device will have a mandatory reboot no matter which exploit you use.</p>
<p>Now that the snapshot has been renamed, iOS has no snapshot to mount so it simply doesn’t. Problem solved. 10/10 - IGN.</p>
<h3 id="a-note-on-the-vfs-exploit-released-by-ian-beer-of-google-project-zero">A note on the VFS exploit released by Ian Beer of Google Project Zero</h3>
<p>The issue with the VFS exploit called “empty_list” is that, due to the nature of the exploit it is usually pretty hard to get it to work reliably. It has been used, however, in both Electra and Unc0ver Jailbreaks because it doesn’t require a paid Apple Developer Account compared to the other exploit released by Ian Beer called MPTCP which is almost bulletproof but requires the Multi-Path entitlement which is not available without a Paid developer account.</p>
<p>Of course, not requiring a paid developer account, even though getting it to work is an exercise in futility sometimes, this seems to be prefered by the general public - that is until they learn about Ignition and other signing services who sign for free the MPTCP version.</p>
<h3 id="stars">Stars</h3>
<p>Star 1: Not a real spyware, just a nice name because WebKitness.</p>
<h3 id="special-thanks">Special thanks</h3>
<ul>
<li>Jonathan Levin for his <a href="http://newosxbook.com/index.php">books</a>, tools and impressive patience with me and my odd questions - YOU ROCK!</li>
<li>@pwn20wnd for pushing me to learn more (and more) being supportive, and findinding errors in the write-up :) </li>
<li>ETA Folks / reditters / naggers for making me laugh from time to time </li>
<li>IBSparkes for answering many of my questions during all these months</li>
<li>stek29 for answering my weird memory related questions</li>
</ul>
<h3 id="license-for-the-diagrams">License for the diagrams</h3>
<p>The diagrams are all built by myself in a tedious process, however, I license them as MIT. Use them as you please as long as you credit me.</p>
<h3 id="errare-humanum-est">Errare humanum est!</h3>
<p>If you find anything wrong in the article feel free to trash-talk me on reddit or better yet, to tell me on Twitter :P</p>The Jailbreaking process has long been a mysterious process where the iOS system suddenly gets unlocked out of Apple’s shackles after running an application for a few seconds. For a very long time, exactly what happened during the runtime of that application was largely unknown and even today as of iOS 11 (12 actually), the end-user (be that casual user, eta folk, reditter or nagger) remains largely oblivious about the processes going on. In this blog post, I am going to try to explain the main elements of a jailbreak as they were implemented and used historically. This post is not all-encompassing and various jailbreak tools for various iOS versions may use different patches and techniques, but they do boil down mostly to what you are about to read.What Is Virtual Memory (wip)2018-09-14T00:00:00+00:002018-09-14T00:00:00+00:00https://geosn0w.github.io/What-is-Virtual-Memory%20(WIP)<p>The concept of virtual memory is nothing new but for many beginners in computer science and security research it is still a hard thing to understand, so I decided to put together a write-up.
The Virtual Memory is used on most operating systems to date. iOS, Android, macOS, Windows, Linux, etc. The whole idea behind Virtual Memory is that each application running on the system has its own address space and it is completely oblivious to the existence of other processes. In other terms, each running program thinks it is the only one running and all the memory belongs to it to do things at its heart content.</p>
<p>The reality is, of course, different. Several programs have to share a limited resource - the RAM or Random Access Memory. That can be anything from a few megabytes to a few gigabytes, but it is still limited. If you only have one single program running at a time (such is the case with Arduino today and was with 8-Bit computers in the 1980s) that should not really be a problem, but when you have to run multiple programs at the same time the memory limitation becomes a thing that hits you hard.</p>
<p>So let’s say we have a computer that has as little as 256 MB of RAM. This is what is called the <code class="language-plaintext highlighter-rouge">Physical Memory</code>. This is what you pay for when you buy a RAM stick (or bought before certain companies decided it is a good idea to solder the RAM to the motherboard and make impossible to upgrade). Of course, you may run a single program fine (given the program can fit in these constraints) but you would have issues running multiple programs and even if you could, running programs directly into the physical memory results in Memory Segmentation.</p>
<p>Memory Segmentation happens when multiple programs run at the same time on the Physical Memory and then quit. Let’s say we have two programs. Program A and Program B. Let’s say Program B is 512 KB in size and Program A is 1 Megabyte. They run fine and then Program B quits. The 512 KB space Program B used to occupy in the Physical Memory is now empty and can be allocated but if the next Program that has to run needs more than that it will be allocated elsewhere. The smaller these gaps the bigger the chances they will never be allocated pretty much creating holes in the memory that do not hold any data and cannot be used either. You would end up running out of memory just due to segmentation, given enough programs run and quit in a time frame.</p>
<p>So, as you can see, the fact that nowadays programs tend to be very big and sometimes require more RAM than you actually have and the fact that Memory Segmentation is pretty much a thing have facilitated the advent of Virtual Memory. The Virtual Memory does not physically exist as the physical one, but it uses the physical memory.</p>
<p>MIPS promises a 32-Bit address space to every program. That is 4GB of address space. If you have a 4GB stick of RAM you may think you can successfully run at least a program without Virtual Memory and then you realize the Operating System is also a thing and it also sucks a lot of that sweet RAM. So here is where Virtual Memory comes.</p>
<p>Let’s say we have 256 MB of RAM and we run programs with 32-Bit Address Spaces. That means 4GB of RAM for each program. How the hell would that fit? It won’t. But we can make it think it would. The Virtual Memory pretty much ensures that each process gets its 4GB address space but it is a virtual one. The addresses are VA (Virtual Address) not PA (Physical Address). A table will pretty much contain the virtual address and its physical address equivalent. So when the program runs, this table will help with the translation from virtual to physical. The processor has a component called the MMU or the Memory Management Unit. This piece of hardware handles something called “Lookup Table” which handles the translation. Of course, the thing would still not fit in the physical memory so here comes the concept of Memory Pages which are pretty much small (usually 4KB) chunks of memory. The pages that are required at the moment are kept in the physical memory for ease of access and everything else is kept on the Disk. The above-mentioned tables know which virtual address resolves to a physical address and which virtual address resolves to disk.</p>
<p>WORK IN PROGRESS - TO BE CONTINUED!</p>The concept of virtual memory is nothing new but for many beginners in computer science and security research it is still a hard thing to understand, so I decided to put together a write-up. The Virtual Memory is used on most operating systems to date. iOS, Android, macOS, Windows, Linux, etc. The whole idea behind Virtual Memory is that each application running on the system has its own address space and it is completely oblivious to the existence of other processes. In other terms, each running program thinks it is the only one running and all the memory belongs to it to do things at its heart content.An introduction to x86 Intel Assembly For Reverse Engineering2018-06-07T00:00:00+00:002018-06-07T00:00:00+00:00https://geosn0w.github.io/An-Introduction-To-Intel-x86-Assembly<p>When I first started Reverse Engineering, I was looking into something, to begin with. I eventually decided to start with understanding assembly because after all, that’s the best you can get when the source code isn’t publicly available unless you find pleasure in reading 1s and 0s or HEX dumps. A few decades ago, a lot of software used to be written in assembly language specific to the CPUs at the time.</p>
<p>I remember writing assembly code for the 6502 CPU back on the Commodore 64 because sometimes, the BASIC was just too slow. It wasn’t really fun. Nowadays, high-level programming languages are way better in terms of speed and ease of use, however, the assembly language is still actively used where very good control over the hardware has to be achieved and for reverse engineering.</p>
<p>Reverse Engineering is, basically, just a better understand of computers and how they work. You don’t essentially learn how to hack or how to reverse engineer, you just learn how computer work. When I first started, I needed to choose a platform because Reverse Engineering can involve different steps depending on the target CPU. I started with Intel x86 (IA-32). This is what I am going to cover in this write-up, and hopefully, this will help beginners understand the basics a bit better.</p>
<h3 id="nota-bene">Nota Bene!</h3>
<p>A very important thing you need to keep in mind when you learn how to read and interpret assembly is that each CPU has a different set of instructions which interact in a different way with one another. Even the mnemonics are different from a CPU architecture to another. For example, the x86 Intel CPU has different instructions compared to the armv7 CPU. While some mnemonics may match, some of them are present on architecture but not in the others. Usually, the reference manuals contain a lot of details about each instruction.</p>
<h3 id="mind-the-compiler">Mind the compiler</h3>
<p>Today’s technology is pretty reliable, it works fast and the speed has long become a requirement when we buy a computer. For computer programs to work fast, compilers, those programs that interpret your C, C++, C#, etc. source code and transform it into machine-readable code, usually add and remove pieces of code from the final binary. This is done for optimization purposes. Either to remove useless CPU cycles or to diminish the RAM footprint. The problem is that when we start reversing a binary it is a bit hard to tell what belongs to the actual program logic and what is added for optimization by the compiler.</p>
<p>A good technique for beginner reverse engineers is to focus more on understanding the flow of the program (by seeking and understanding where the program calls a function, jumps to a different location, updates or checks a variable, etc.) than on the whole thing. It is also a good idea to understand the structure of a procedure in assembly. It would help you understand why you can see a pattern of instructions at the beginning of every function. This is called the function prologue, but about this, we’re talking later on.</p>
<h3 id="cpu-registers">CPU Registers</h3>
<p>Before starting your journey onto the IA-32 assembly, it’s a very good idea to learn more about the architecture itself. The CPU has what is called “registers”. They are pretty much a very fast but limited memory on the microprocessor. The microprocessor can access these registers and retrieve the data way faster than it could do from RAM. The problem is, there are only a few of them and some registers are not general purpose, meaning they can’t really be used for everything. What can’t be fitted in the registers, lies in the RAM.</p>
<p>The IA-32 CPUs have 8 general purpose 32-Bit registers. Of course, these CPUs have way more registers than that, but only eight of them are truly general purpose. These registers are very important and you will find them scattered all over the place in the assembly output of any binary disassembler. A list of the available registers and a brief description is provided below.</p>
<p>EAX, EBX, ECX, and EDX are general purpose registers used for various operations. ECX is sometimes used as a counter by repetitive instructions.</p>
<p>EBP and ESP are the Stack Base Pointer and the Stack Pointer. Together, these two create the Stack Frame.</p>
<p>EDI and ESI are the Destination Index and Source Index registers and is used when dealing with the memory copying.</p>
<p>The preceding “E” in the register name is standing for “extended”. That is because the name is carried over from the 16-bit architecture where the registers were, as you may have figured out, 16-bit wide.</p>
<p>Here is a diagram I’ve made to help you understand the registers and their 16-Bit counterparts.</p>
<p align="center">
<img src="https://user-images.githubusercontent.com/15067741/41131632-4047f37e-6ac5-11e8-84e2-827c63a231af.png" alt="IA-32 Registers Diagram" />
</p>
<h3 id="cpu-flags">CPU Flags</h3>
<p>Aside from the registers, the CPU also has flags which are used during various operations. The flags are contained in the big EFLAGS special register. These flags are used for various purposes and they can manage the processor modes, and states and they can also store the logical state and are heavily used by conditional jump instructions. For example, the JNE instruction which stands for Jump If Not Equal will always use the ZF (Zero Flag) set by a previous CMP (compare) instruction. A CMP instruction takes two operands and subtracts one from the other. If they are equal, the Zero Flag will be set so the following JNE instruction will see that and skip the branch. At the same time, a JE (Jump if Equal) would jump if the flag is set.</p>
<h3 id="arithmetics-on-the-ia-32">Arithmetics on the IA-32</h3>
<p>The IA-32 instruction set contains six instructions for arithmetic purposes.</p>
<p>ADD - Used: ADD Operand1, Operand2 - The result is stored in Operand1</p>
<p>SUB - Used: SUB Operand1, Operant2 - The result is stored in Operand1</p>
<p>DIV - Used: DIV Operand - Divides the 64-bit value from EDX:EAX by the unsigned operand specified.</p>
<p>MUL - Used: MUL Operand - Multiplies the Unsigned operand specified, by EAX and stores the result as 64-bit in EDX:EAX</p>
<p>IDIV - Used: IDIV Operand - Divides the 64-bit value from EDX:EAX by the signed operand specified.</p>
<p>IMUL - Used: - Multiplies the signed operand specified, by EAX and stores the result as 64-bit in EDX:EAX</p>
<h3 id="example">Example</h3>
<p>In this example, you can see the CMP, JNE and some general purpose registers used in a block of code that resembles the if conditions in a high-level programming language.</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">ADD</span> <span class="n">EAX</span><span class="p">,</span> <span class="mi">12</span> <span class="p">;</span> <span class="n">We</span> <span class="n">add</span> <span class="mi">12</span> <span class="n">to</span> <span class="n">the</span> <span class="n">EAX</span> <span class="k">register</span><span class="err">'</span><span class="n">s</span> <span class="n">value</span>
<span class="n">CMP</span> <span class="n">EAX</span><span class="p">,</span> <span class="mh">0xC</span> <span class="p">;</span> <span class="n">We</span> <span class="n">compare</span> <span class="n">EAX</span> <span class="n">with</span> <span class="n">the</span> <span class="n">hex</span> <span class="n">representation</span> <span class="n">of</span> <span class="n">decimal</span> <span class="mi">12</span>
<span class="n">JNE</span> <span class="mh">0x1001FFee1</span> <span class="p">;</span> <span class="n">If</span> <span class="n">the</span> <span class="n">comparison</span> <span class="n">results</span> <span class="n">that</span> <span class="n">EAX</span> <span class="o">=</span> <span class="mi">12</span><span class="p">,</span> <span class="n">the</span> <span class="n">ZF</span> <span class="n">is</span> <span class="n">set</span> <span class="n">and</span> <span class="n">the</span> <span class="n">JNE</span> <span class="n">won</span><span class="err">'</span><span class="n">t</span> <span class="n">proceed</span> <span class="n">to</span> <span class="n">the</span> <span class="n">address</span> <span class="n">specified</span><span class="p">.</span>
<span class="n">MOV</span> <span class="n">EDI</span><span class="p">,</span> <span class="p">[</span><span class="n">ECX</span><span class="o">+</span><span class="mh">0x4b2</span><span class="p">]</span> <span class="p">;</span> <span class="n">Move</span> <span class="n">whatever</span> <span class="n">is</span> <span class="n">at</span> <span class="n">ECX</span> <span class="o">+</span> <span class="mh">0x4b2</span> <span class="n">offset</span> <span class="n">into</span> <span class="n">the</span> <span class="n">EDI</span> <span class="k">register</span>
<span class="n">JMP</span> <span class="mh">0x1001DDe1</span> <span class="p">;</span> <span class="n">Unconditional</span> <span class="n">jump</span> <span class="n">to</span> <span class="n">that</span> <span class="n">address</span><span class="p">.</span>
</code></pre></div></div>
<p>The unconditional jump would not have the chance to be executed if the above JNE executed. Since the comparison on which the JNE instruction relies resulted in the two values being equal, the ZF (Zero Flag) is set and the Jump If Not Zero (JNZ) is skipped. The next instruction after the conditional jump is executed until the JMP which is an unconditional jump. This means that the jump will happen no matter what, as long as the CPU can reach the execution of this instruction.</p>
<p>You can see this sort of comparison followed by a conditional jump in many programs. The closest high-level programming concept that matches this assembly snippet would be an If Condition or other related control flow statements.</p>
<p>For example, the following code contains a simple If - Else statement. Let’s see how will this be represented in the assembly after GCC compiler does its job.</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include <stdlib.h>
#include <stdio.h>
</span>
<span class="kt">int</span> <span class="nf">compare</span><span class="p">(){</span>
<span class="kt">int</span> <span class="n">x</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="kt">int</span> <span class="n">y</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="kt">int</span> <span class="n">z</span> <span class="o">=</span> <span class="n">x</span> <span class="o">+</span> <span class="n">y</span><span class="p">;</span>
<span class="k">return</span> <span class="n">z</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">(){</span>
<span class="kt">int</span> <span class="n">x</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="n">x</span> <span class="o">=</span> <span class="mi">12</span><span class="p">){</span>
<span class="n">compare</span><span class="p">();</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nl">_compare:</span>
<span class="mo">00001</span><span class="n">f40</span> <span class="n">push</span> <span class="n">ebp</span> <span class="p">;</span> <span class="n">XREF</span><span class="o">=</span><span class="mh">0x10ac</span><span class="p">,</span> <span class="n">_main</span><span class="o">+</span><span class="mi">30</span>
<span class="mo">00001</span><span class="n">f41</span> <span class="n">mov</span> <span class="n">ebp</span><span class="p">,</span> <span class="n">esp</span>
<span class="mo">00001</span><span class="n">f43</span> <span class="n">sub</span> <span class="n">esp</span><span class="p">,</span> <span class="mh">0xc</span>
<span class="mo">00001</span><span class="n">f46</span> <span class="n">mov</span> <span class="n">dword</span> <span class="p">[</span><span class="n">ss</span><span class="o">:</span><span class="n">ebp</span><span class="o">+</span><span class="n">var_4</span><span class="p">],</span> <span class="mh">0x2</span>
<span class="mo">00001</span><span class="n">f4d</span> <span class="n">mov</span> <span class="n">dword</span> <span class="p">[</span><span class="n">ss</span><span class="o">:</span><span class="n">ebp</span><span class="o">+</span><span class="n">var_8</span><span class="p">],</span> <span class="mh">0x1</span>
<span class="mo">00001</span><span class="n">f54</span> <span class="n">mov</span> <span class="n">eax</span><span class="p">,</span> <span class="n">dword</span> <span class="p">[</span><span class="n">ss</span><span class="o">:</span><span class="n">ebp</span><span class="o">+</span><span class="n">var_4</span><span class="p">]</span>
<span class="mo">00001</span><span class="n">f57</span> <span class="n">add</span> <span class="n">eax</span><span class="p">,</span> <span class="n">dword</span> <span class="p">[</span><span class="n">ss</span><span class="o">:</span><span class="n">ebp</span><span class="o">+</span><span class="n">var_8</span><span class="p">]</span>
<span class="mo">00001</span><span class="n">f5a</span> <span class="n">mov</span> <span class="n">dword</span> <span class="p">[</span><span class="n">ss</span><span class="o">:</span><span class="n">ebp</span><span class="o">+</span><span class="n">var_C</span><span class="p">],</span> <span class="n">eax</span>
<span class="mo">00001</span><span class="n">f5d</span> <span class="n">mov</span> <span class="n">eax</span><span class="p">,</span> <span class="n">dword</span> <span class="p">[</span><span class="n">ss</span><span class="o">:</span><span class="n">ebp</span><span class="o">+</span><span class="n">var_C</span><span class="p">]</span>
<span class="mo">00001</span><span class="n">f60</span> <span class="n">add</span> <span class="n">esp</span><span class="p">,</span> <span class="mh">0xc</span>
<span class="mo">00001</span><span class="n">f63</span> <span class="n">pop</span> <span class="n">ebp</span>
<span class="mo">00001</span><span class="n">f64</span> <span class="n">ret</span>
<span class="p">;</span> <span class="n">endp</span>
<span class="n">_main</span><span class="o">:</span>
<span class="mo">00001</span><span class="n">f70</span> <span class="n">push</span> <span class="n">ebp</span> <span class="p">;</span> <span class="n">Push</span> <span class="n">the</span> <span class="n">Stack</span> <span class="n">Base</span> <span class="n">Pointer</span>
<span class="mo">00001</span><span class="n">f71</span> <span class="n">mov</span> <span class="n">ebp</span><span class="p">,</span> <span class="n">esp</span>
<span class="mo">00001</span><span class="n">f73</span> <span class="n">sub</span> <span class="n">esp</span><span class="p">,</span> <span class="mh">0x18</span> <span class="p">;</span> <span class="n">Subtract</span> <span class="mi">24</span> <span class="n">from</span> <span class="n">the</span> <span class="n">Stack</span> <span class="n">Pointer</span>
<span class="mo">00001</span><span class="n">f76</span> <span class="n">mov</span> <span class="n">dword</span> <span class="p">[</span><span class="n">ss</span><span class="o">:</span><span class="n">ebp</span><span class="o">+</span><span class="n">var_4</span><span class="p">],</span> <span class="mh">0x0</span>
<span class="mo">00001</span><span class="n">f7d</span> <span class="n">mov</span> <span class="n">dword</span> <span class="p">[</span><span class="n">ss</span><span class="o">:</span><span class="n">ebp</span><span class="o">+</span><span class="n">var_8</span><span class="p">],</span> <span class="mh">0x0</span> <span class="p">;</span> <span class="n">Clearing</span> <span class="n">purposes</span><span class="o">?</span>
<span class="mo">00001</span><span class="n">f84</span> <span class="n">cmp</span> <span class="n">dword</span> <span class="p">[</span><span class="n">ss</span><span class="o">:</span><span class="n">ebp</span><span class="o">+</span><span class="n">var_8</span><span class="p">],</span> <span class="mh">0xc</span> <span class="p">;</span> <span class="n">This</span> <span class="n">is</span> <span class="n">where</span> <span class="n">the</span> <span class="n">comparision</span> <span class="n">is</span> <span class="n">done</span> <span class="n">with</span> <span class="mi">12</span><span class="p">.</span>
<span class="mo">00001</span><span class="n">f88</span> <span class="n">jne</span> <span class="mh">0x1f9b</span> <span class="p">;</span> <span class="n">Jump</span> <span class="k">if</span> <span class="n">not</span> <span class="n">equal</span> <span class="p">(</span><span class="n">pretty</span> <span class="n">much</span> <span class="n">executes</span> <span class="n">the</span> <span class="n">ELSE</span><span class="p">)</span>
<span class="mo">00001</span><span class="n">f8e</span> <span class="n">call</span> <span class="n">_compare</span> <span class="p">;</span> <span class="n">call</span> <span class="nf">compare</span><span class="p">();</span>
<span class="mo">00001</span><span class="n">f93</span> <span class="n">mov</span> <span class="n">dword</span> <span class="p">[</span><span class="n">ss</span><span class="o">:</span><span class="n">ebp</span><span class="o">+</span><span class="n">var_C</span><span class="p">],</span> <span class="n">eax</span>
<span class="mo">00001</span><span class="n">f96</span> <span class="n">jmp</span> <span class="mh">0x1fa2</span>
<span class="mo">00001</span><span class="n">f9b</span> <span class="n">mov</span> <span class="n">dword</span> <span class="p">[</span><span class="n">ss</span><span class="o">:</span><span class="n">ebp</span><span class="o">+</span><span class="n">var_4</span><span class="p">],</span> <span class="mh">0x0</span> <span class="p">;</span> <span class="n">This</span> <span class="n">is</span> <span class="n">the</span> <span class="n">beginning</span> <span class="n">of</span> <span class="n">the</span> <span class="n">ELSE</span> <span class="n">statement</span>
<span class="mo">00001</span><span class="n">fa2</span> <span class="n">mov</span> <span class="n">eax</span><span class="p">,</span> <span class="n">dword</span> <span class="p">[</span><span class="n">ss</span><span class="o">:</span><span class="n">ebp</span><span class="o">+</span><span class="n">var_4</span><span class="p">]</span> <span class="p">;</span> <span class="n">Return</span> <span class="mi">0</span><span class="p">;</span>
<span class="mo">00001</span><span class="n">fa5</span> <span class="n">add</span> <span class="n">esp</span><span class="p">,</span> <span class="mh">0x18</span>
<span class="mo">00001</span><span class="n">fa8</span> <span class="n">pop</span> <span class="n">ebp</span> <span class="p">;</span> <span class="n">Pop</span> <span class="n">the</span> <span class="n">Stack</span> <span class="n">Base</span> <span class="n">Pointer</span>
<span class="mo">00001</span><span class="n">fa9</span> <span class="n">ret</span> <span class="p">;</span> <span class="n">Bail</span> <span class="n">out</span>
</code></pre></div></div>
<p>As you can see, only a few of the instructions are relevant for our If - Else statement. The rest are either the compiler’s way of pushing the “X” variable to the stack, the function prologue, epilogue, and calls.
In order to understand the program flow, you have to ignore the bits you don’t understand and focus on the ones that make sense first.</p>
<h3 id="function-calls">Function calls</h3>
<p>As you can see, the function calls are done using the CALL instruction which accepts a single operand. This is the address of the function to jump to. Once the CALL instruction is hit, it will push the current Instruction Pointer to the stack (so that it the program can continue from where it left when the called function RETurns), and then it jumps to address of the called function. In the above example, the CALL happens at address <code class="language-plaintext highlighter-rouge">0x00001f8e</code> and the call instruction calls compare() which is at address <code class="language-plaintext highlighter-rouge">0x00001f40</code>.</p>
<p>In order to return to the callee, the function ends with a RET instruction. Additionally, one can instruct RET to increment the Stack Pointer (ESP) by a number of bytes after the instruction pointer is popped.</p>
<h3 id="using-inline-assembly-in-c-and-c">Using inline assembly in C and C++</h3>
<p>Some compilers allow you to write inline assembly code and embed it into your C and C++ code. This is done using the <code class="language-plaintext highlighter-rouge">__asm__</code> notation or simply using the <code class="language-plaintext highlighter-rouge">asm()</code>. The IA-32 assembly can be represented in different syntaxes. The Intel syntax is the most used but you can chose the AT&T syntax too if you’re into that. Most debuggers and reverse engineering tools, like GDB, allow you to set the disassembly syntax.</p>
<p>Here’s a quick example of a C program that also involves assembly:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include <stdlib.h>
#include <stdio.h>
</span>
<span class="kt">int</span> <span class="n">source</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
<span class="kt">int</span> <span class="n">destination</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">(){</span>
<span class="n">asm</span> <span class="p">(</span><span class="s">"mov %1, %0</span><span class="se">\n\t</span><span class="s">"</span>
<span class="s">"add $4, %0"</span>
<span class="o">:</span> <span class="s">"=r"</span> <span class="p">(</span><span class="n">destination</span><span class="p">)</span>
<span class="o">:</span> <span class="s">"r"</span> <span class="p">(</span><span class="n">source</span><span class="p">)</span>
<span class="p">);</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"The result is %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">destination</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>
<p>I hope you will find this write-up on beginner level IA-32 assembly useful in the future and I wish you good luck in your journey on the land of reverse engineering. Happy CVEing!</p>When I first started Reverse Engineering, I was looking into something, to begin with. I eventually decided to start with understanding assembly because after all, that’s the best you can get when the source code isn’t publicly available unless you find pleasure in reading 1s and 0s or HEX dumps. A few decades ago, a lot of software used to be written in assembly language specific to the CPUs at the time.Hacking the Dino Game from Google Chrome, The Immortal Dinosaur2018-05-28T00:00:00+00:002018-05-28T00:00:00+00:00https://geosn0w.github.io/Hacking-the-Dino-Game-from-Google-Chrome,-The-Immortal-Dinosaur<p>When there is no internet connection available, Google Chrome web browser on Windows and macOS (most likely on Linux too) shows up a page detailing the possible causes as well as a small endless runner game with a dinosaur that has to run, dodge obstacles and accumulate points. The game is relatively simple-minded. A monochrome game area with clouds, cacti, bumps in the ground, a dinosaur, a Hi-Score counter and a current score counter. As levels increase in complexity, the dinosaur will have to dodge cacti, pterodactyls, and so on. The game also inverts the contrast at random points making the background black and the creatures white to simulate a night mode and at the same time to draw player’s attention to the background change making it harder to play for a second, which could prove fatal.</p>
<h3 id="undocumented-features">Undocumented Features</h3>
<p>There’s an undocumented full-screen mode. Undocumented as in “there’s no button to switch to that mode”. The mode can be enabled if you access the game directly from its internal Chrome URL, that is <code class="language-plaintext highlighter-rouge">chrome://dino</code>.</p>
<h3 id="exploring-hacking-possibilities">Exploring hacking possibilities</h3>
<p>Since the game itself is mostly written in JavaScript, it makes hacking very easy. Google Chrome’s built-in Developer Tools contain a console where you can inject code, a debugger, and many other tools that you can find very useful. For the sake of not having the game in full screen, I will disconnect MacBook from the WiFi station and I’ll start tinkering with the game. Keep in mind that this is my original route I followed to hack the game initially while my internet was down one day.</p>
<h3 id="monitoring-the-game-logic">Monitoring the game logic</h3>
<p>By starting the game and opening the “Inspect Element” menu, we can see that the game runs in a div class called “runner-container”. In the right side, we have the “Styles” where CSS is shown. There are a couple “runner-container” components. If we click the “index.NUMBER”, we’re brought to a sub-menu containing a debugger. We can pause, step, run and so on. Let’s restart the game and quickly pause it using the debugger.</p>
<p align="center">
<img src="https://user-images.githubusercontent.com/15067741/40609789-c7837376-623d-11e8-8a07-8926d31258e8.png" />
</p>
<p>Great! Now it says “Paused in debugger”. We’ve also got our first bits of information about the game on the debugger. There is a function called “Runner” with a lot of components that seem to be related to the game logic. Here are some of the components inside the “Runner” function. Amongst other stuff, in the “<strong>proto</strong>” you can see a function called “gameOver()”</p>
<p align="center">
<img src="https://user-images.githubusercontent.com/15067741/40610200-6a65f432-623f-11e8-8e0e-de418a4263b3.png" />
</p>
<p align="center">
<img src="https://user-images.githubusercontent.com/15067741/40609799-cade4da2-623d-11e8-874f-431d82adb0e6.png" />
</p>
<h3 id="hacking-the-game">Hacking the game</h3>
<p>As we identified earlier, there is a function prototype called “gameOver()” that handles exactly what it claims. The original code of the function is the following:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">playSound</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">soundFx</span><span class="p">.</span><span class="nx">HIT</span><span class="p">);</span>
<span class="nx">vibrate</span><span class="p">(</span><span class="mi">200</span><span class="p">);</span>
<span class="k">this</span><span class="p">.</span><span class="nx">stop</span><span class="p">();</span>
<span class="k">this</span><span class="p">.</span><span class="nx">crashed</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>
<span class="k">this</span><span class="p">.</span><span class="nx">distanceMeter</span><span class="p">.</span><span class="nx">achievement</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
<span class="k">this</span><span class="p">.</span><span class="nx">tRex</span><span class="p">.</span><span class="nx">update</span><span class="p">(</span><span class="mi">100</span><span class="p">,</span> <span class="nx">Trex</span><span class="p">.</span><span class="nx">status</span><span class="p">.</span><span class="nx">CRASHED</span><span class="p">);</span>
<span class="c1">// Game over panel.</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="k">this</span><span class="p">.</span><span class="nx">gameOverPanel</span><span class="p">)</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">gameOverPanel</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">GameOverPanel</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">canvas</span><span class="p">,</span>
<span class="k">this</span><span class="p">.</span><span class="nx">spriteDef</span><span class="p">.</span><span class="nx">TEXT_SPRITE</span><span class="p">,</span> <span class="k">this</span><span class="p">.</span><span class="nx">spriteDef</span><span class="p">.</span><span class="nx">RESTART</span><span class="p">,</span>
<span class="k">this</span><span class="p">.</span><span class="nx">dimensions</span><span class="p">);</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">gameOverPanel</span><span class="p">.</span><span class="nx">draw</span><span class="p">();</span>
<span class="p">}</span>
<span class="c1">// Update the high score.</span>
<span class="k">if</span> <span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">distanceRan</span> <span class="o">></span> <span class="k">this</span><span class="p">.</span><span class="nx">highestScore</span><span class="p">)</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">highestScore</span> <span class="o">=</span> <span class="nb">Math</span><span class="p">.</span><span class="nx">ceil</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">distanceRan</span><span class="p">);</span>
<span class="k">this</span><span class="p">.</span><span class="nx">distanceMeter</span><span class="p">.</span><span class="nx">setHighScore</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">highestScore</span><span class="p">);</span>
<span class="p">}</span>
<span class="c1">// Reset the time clock.</span>
<span class="k">this</span><span class="p">.</span><span class="nx">time</span> <span class="o">=</span> <span class="nx">getTimeStamp</span><span class="p">();</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Now that we know how the game handles the collision and the “Game Over” scenario resulted from a collision, we can patch the function using the aforementioned console.
All we need to do is to close the debugger, reload the page, right-click on “Inspect Element” and navigate to the Console. We know that the main function is called “Runner” and the targeted function is called “gameOver”. All we need to do is to overwrite the code of the “gameOver()” function to be nothing so that the game will go on and on. Before we do that, we store the original function in a dummy variable.</p>
<p>In console we’ll write:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">var</span> <span class="nx">dummy</span> <span class="o">=</span> <span class="nx">Runner</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">gameOver</span>
<span class="nx">Runner</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">gameOver</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(){</span>
<span class="p">}</span>
</code></pre></div></div>
<p>At this point, the Dinosaur will be able to simply go through all the obstacles.
Let’s fiddle a bit with the speed of the game too. To do that we play with another function called “setSpeed()” which accepts a number. By changing the value we can change the speed of our dinosaur and get score faster. The maximum score the game gives you is 99999 before it resets back to 0.</p>
<p>In console we’ll write:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">Runner</span><span class="p">.</span><span class="nx">instance_</span><span class="p">.</span><span class="nx">setSpeed</span><span class="p">(</span><span class="mi">6000</span><span class="p">)</span>
</code></pre></div></div>
<p>This will change the speed of the dinosaur to 6000. You can use any other number.</p>
<h3 id="undocumented-trick">Undocumented trick</h3>
<p>I’ve discovered this trick accidentally, but it is pretty neat. Changing the speed to “-1” will make the dinosaur to go backward and the entire game scene follows its backward movement. LOL.</p>
<p>To do that, in the console we’ll write:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">Runner</span><span class="p">.</span><span class="nx">instance_</span><span class="p">.</span><span class="nx">setSpeed</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span>
</code></pre></div></div>
<p>Of course, if you wanna get busy with the game, you should be able to change the sprites too. The same methodology should apply.
Since your game no longer has a collision stop mechanism, it will run forever. If you want to stop it, you need to employ the Console again.</p>
<p>To do that, in the console we’ll write:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">Runner</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">gameOver</span> <span class="o">=</span> <span class="nx">dummy</span>
</code></pre></div></div>
<p>This will replace our modified “gameOver” function with the factory content and will, therefore, bring back a working collision detection and “Game Over” to the game.</p>
<p align="center">
<img src="https://user-images.githubusercontent.com/15067741/40609987-869df9a2-623e-11e8-8195-01eee9a672a4.png" />
</p>When there is no internet connection available, Google Chrome web browser on Windows and macOS (most likely on Linux too) shows up a page detailing the possible causes as well as a small endless runner game with a dinosaur that has to run, dodge obstacles and accumulate points. The game is relatively simple-minded. A monochrome game area with clouds, cacti, bumps in the ground, a dinosaur, a Hi-Score counter and a current score counter. As levels increase in complexity, the dinosaur will have to dodge cacti, pterodactyls, and so on. The game also inverts the contrast at random points making the background black and the creatures white to simulate a night mode and at the same time to draw player’s attention to the background change making it harder to play for a second, which could prove fatal.How to Find Offsets For iOS Exploits In The Kernel2018-05-13T00:00:00+00:002018-05-13T00:00:00+00:00https://geosn0w.github.io/How-to-Find-Offsets-For-IOS-Exploits-In-The-Kernel<p>This write-up uses as an example the Trident project by benjamin-42. The offsets are for the components this particular project requires, but the methodology and the information can easily be adapted to other iOS versions, devices, and projects. Each exploit requires a different set of offsets for various kernel components and each offset is found in a different way, but I believe this information should be useful for beginners. I am gonna use the iPod Touch 5th Generation for this write-up.</p>
<p>I was working on a private iOS 8.4.1 Jailbreak for my iPod Touch 5th Generation for practicing purposes and I’ve decided to use <code class="language-plaintext highlighter-rouge">CVE-2016-4655</code> in order to leak the Kernel Base. The Kernel base will be required, especially since I need to patch a few things up. The iOS 8.4.1 Kernel is randomized using kASLR by iBoot at every boot of the system so we’ll need to calculate the randomized address of the components we wanna patch. Let’s take <code class="language-plaintext highlighter-rouge">_kernel_pmap</code> as an example. If I disassemble the <code class="language-plaintext highlighter-rouge">kernelcache.release.n78</code> using IDA Pro or Hopper Disassembler, the <code class="language-plaintext highlighter-rouge">_kernel_pmap</code> can be located at address <code class="language-plaintext highlighter-rouge">0x803a311c</code> in the <code class="language-plaintext highlighter-rouge">__DATA segment</code>, but this will not remain true for the live running kernel, so I can’t just patch PMAP using that address. In this case, I need to find the offset, add the Kernel Base and calculate the live, slid address of <code class="language-plaintext highlighter-rouge">_kernel_pmap</code>.</p>
<p>Of course, <code class="language-plaintext highlighter-rouge">_kernel_pmap</code> is not the only component that needs patching in a jailbreak, and for each component, the address you find in IDA or in Hopper won’t match the live Kernel because of kASLR (Kernel Address Space Layout Randomization). Of course, since my example is on iOS 8.4.1, and therefore before the changes implemented in iOS 10 regarding the encryption of the firmware, before we can do any sort of disassembly we need to decrypt the Kernel with the appropriate Key and IV. These can be located, fortunately, on TheiPhoneWiki for all 32-Bit devices and some 64-Bit devices too.</p>
<p>When you’re building a jailbreak, there is no legal notice that you MUST do everything from scratch or otherwise your PC will catch fire. Nope. You can reuse parts of someone else’s code (publicly released open source exploits, PoCs, etc.), as long as you give proper credits and you respect the license. In my case, I was going to use Trident by benjamin-42 on GitHub, but I realized that the <code class="language-plaintext highlighter-rouge">offsetfinder.c</code> from his project does not have the offsets for iPod Touch 5th Generation on iOS 8.4.1 which means that the project is totally useless for my device until I find the correct offsets. That was the reason I’ve decided to put together this write-up.</p>
<p>So, without further ado, let’s begin() our journey!</p>
<h3 id="getting-started">Getting started.</h3>
<p>At first, we need to obtain ourselves a copy of the iOS 8.4.1 (or the version you intend to use this for) Kernel. Fortunately, the decryption keys are available, so we don’t need to dump the kernel from the memory of the device (much more painful and hard to do and requires exploit and more coding). However, It’s not pink flowers and unicorns here either. We need to decrypt the kernel using <code class="language-plaintext highlighter-rouge">xpwntool</code>. All the tools referred in this write-up will be linked at the end of the article. Before we can decrypt it, we need to grab it. We have two options: Either download the whole iOS 8.4.1 IPSW for iPod Touch 5th Generation (in my case), which may not be that bad depending on your internet speed, or download only the <code class="language-plaintext highlighter-rouge">kernelcache.release.n78</code> which is better for me since I am currently living in a part of Italy where the internet speed is not very great.</p>
<h3 id="obtaining-the-kernelcachereleasexx-file">Obtaining the <code class="language-plaintext highlighter-rouge">kernelcache.release.xx</code> file</h3>
<p>For this task, we can use <code class="language-plaintext highlighter-rouge">PZB</code> or <code class="language-plaintext highlighter-rouge">Partial Zip Browser</code> by @tihmstar. The source code is available at the end of the write-up.
Once we have the source code, we can compile it and run it in Terminal.
PZB has the following syntax: <code class="language-plaintext highlighter-rouge">./pzb [parameter] <url to zip></code>.</p>
<p>With this in place, we can first run <code class="language-plaintext highlighter-rouge">./pzb -l <IPSW LINK></code> and see the name of all the files, including the Kernel file which in my case is called <code class="language-plaintext highlighter-rouge">kernelcache.release.n78</code>. Then we can simply run <code class="language-plaintext highlighter-rouge">./pzb -g file_to_download <IPSW LINK></code> and get the file. My final command would be <code class="language-plaintext highlighter-rouge">./pzb -g kernelcache.release.n78 http://appldnld.apple.com/ios8.4.1/031-31324-20150812-5AAFE21E-3C90-11E5-BEE3-6A1C3A53DB92/iPod5,1_8.4.1_12H321_Restore.ipsw</code></p>
<p>Now that I have my <code class="language-plaintext highlighter-rouge">kernelcache.release.n78</code> in my User directory (<code class="language-plaintext highlighter-rouge">geosn0w</code> directory in my case), I am able to run it through <code class="language-plaintext highlighter-rouge">xpwntool</code> to decrypt it. Xpwntool’s syntax for our needs looks like this <code class="language-plaintext highlighter-rouge">xpwntool <infile> <outfile> [-k <key>] [-iv <key>]</code>
Both the <code class="language-plaintext highlighter-rouge">Key</code> and the <code class="language-plaintext highlighter-rouge">IV</code> can be found on TheiPhoneWiki on the Firmware page. Each device has a different <code class="language-plaintext highlighter-rouge">Key</code> and a different <code class="language-plaintext highlighter-rouge">IV</code> for the same iOS version. The reason for that is that the keys used to be generated using the baked in <code class="language-plaintext highlighter-rouge">GID key</code> that cannot be retrieved. Using an <code class="language-plaintext highlighter-rouge">iBoot</code> or a <code class="language-plaintext highlighter-rouge">SecureROM</code> exploit one can access the built-in <code class="language-plaintext highlighter-rouge">AES Engine</code> and generate the keys from the KBAGS of the encrypted files. A tedious process that requires 0day on newer devices. Fortunately, Apple stopped encrypting most components in iSO 10.x</p>
<p>My Final command on Xpwntool is <code class="language-plaintext highlighter-rouge">/Users/geosn0w/Desktop/ToolChain/Pentesting\ Tools\ \&\ Other/xpwntool /Users/geosn0w/Desktop/kernelcache.release.n78 /Users/geosn0w/Desktop/kernelcache.release.DECRYPTED -k e7904495a19966d622389ce0e1113f4f00e0fc7c0fa65c4d66e79dd12450edf9 -iv c96b701e3dc9ae4d07bf722a4cb50011</code></p>
<p>The command should create a new file called <code class="language-plaintext highlighter-rouge">kernelcache.release.DECRYPTED</code> on my Desktop and the file should be recognized as <code class="language-plaintext highlighter-rouge">Mach-O executable arm_v7</code> if you run it through the <code class="language-plaintext highlighter-rouge">file</code> command in terminal. Now I am able to finally open the Kernel file in IDA or in Hopper Disassembler and look for what I need, but what do I need?</p>
<h3 id="making-a-note-of-whos-offsets-we-need">Making a note of who’s offsets we need</h3>
<p>As I said, I am building a tool for iOS 8.4.1, iPod Touch 5th Generation and I use the <code class="language-plaintext highlighter-rouge">Trident</code> project as my beginning point. The project lacks the proper offsets for my device, so I need to find them manually. When I run the project as is, it bails out and says that the device is unsupported. No wonder why there is a function that checks whether the project has the right offsets. No patching can be done without knowing where in the memory is the thing you wanna patch.</p>
<p>Taking a look at the <code class="language-plaintext highlighter-rouge">offsetfinder.h</code> header file inside the <code class="language-plaintext highlighter-rouge">Trident</code> source code, I can see a list of offsets needed so I know what I need to find. The list goes like this in my case.</p>
<figure class="highlight"><pre><code class="language-c" data-lang="c"><span class="c1">// OSSerializer::serialize</span>
<span class="kt">uint32_t</span> <span class="nf">find_OSSerializer_serialize</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span>
<span class="c1">// OSSymbol::getMetaClass</span>
<span class="kt">uint32_t</span> <span class="nf">find_OSSymbol_getMetaClass</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span>
<span class="c1">// calend_gettime</span>
<span class="kt">uint32_t</span> <span class="nf">find_calend_gettime</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span>
<span class="c1">// _bufattr_cpx</span>
<span class="kt">uint32_t</span> <span class="nf">find_bufattr_cpx</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span>
<span class="c1">// clock_ops</span>
<span class="kt">uint32_t</span> <span class="nf">find_clock_ops</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span>
<span class="c1">// _copyin</span>
<span class="kt">uint32_t</span> <span class="nf">find_copyin</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span>
<span class="c1">// BX LR</span>
<span class="kt">uint32_t</span> <span class="nf">find_bx_lr</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span>
<span class="c1">// write_gadget: str r1, [r0, #0xc] ; bx lr</span>
<span class="kt">uint32_t</span> <span class="nf">find_write_gadget</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span>
<span class="c1">// vm_kernel_addrperm</span>
<span class="kt">uint32_t</span> <span class="nf">find_vm_kernel_addrperm</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span>
<span class="c1">// kernel_pmap</span>
<span class="kt">uint32_t</span> <span class="nf">find_kernel_pmap</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span>
<span class="c1">// flush_dcache</span>
<span class="kt">uint32_t</span> <span class="nf">find_flush_dcache</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span>
<span class="c1">// invalidate_tlb</span>
<span class="kt">uint32_t</span> <span class="nf">find_invalidate_tlb</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span>
<span class="c1">// task_for_pid</span>
<span class="kt">uint32_t</span> <span class="nf">find_task_for_pid</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span>
<span class="c1">// setreuid</span>
<span class="kt">uint32_t</span> <span class="nf">find_setreuid</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span>
<span class="c1">// setreuid cred update</span>
<span class="kt">uint32_t</span> <span class="nf">find_setreuid_cred_update</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span>
<span class="c1">// pid_check_addr offset</span>
<span class="kt">uint32_t</span> <span class="nf">find_pid_check</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span>
<span class="c1">// posix_check_ret_addr offset</span>
<span class="kt">uint32_t</span> <span class="nf">find_posix_check</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span>
<span class="c1">// mac_proc_check_ret_addr offset</span>
<span class="kt">uint32_t</span> <span class="nf">find_mac_proc_check</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span></code></pre></figure>
<p>Okay, so looks like I have to find 18 different offsets in the kernel just to get the Trident project to work.
At first, let’s understand how the real address of what we need is calculated. First, before we can calculate anything, we need to grab the Kernel Base, because everything else will be relative to it. This is where the <code class="language-plaintext highlighter-rouge">CVE-2016-4655</code> is very useful. This vulnerability works all the way up to iOS 9.3.4 (patched in iOS 9.3.5), so we can use this info leak vulnerability to grab the Kernel Base and then calculate the real address of the functions we wanna patch in the live kernel.</p>
<p>Let’s take an example:
Let’s assume that <code class="language-plaintext highlighter-rouge">_kernel_pmap</code>’s unslid address is <code class="language-plaintext highlighter-rouge">0x803a311c</code>. From the <code class="language-plaintext highlighter-rouge">unslid kernel base</code> to <code class="language-plaintext highlighter-rouge">0x803a311c</code> we have an <code class="language-plaintext highlighter-rouge">offset</code> of <code class="language-plaintext highlighter-rouge">0x3a211c</code>. This would be the offset we need if the kernel was unslid in the memory, but the kernel is randomized so this offset means nothing. Remember that we considered our offset relative to the unslid Kernel Base? Well, if we grab the slid <code class="language-plaintext highlighter-rouge">Kernel Base</code> and we add this offset, we are able to tell exactly where in the memory is the <code class="language-plaintext highlighter-rouge">_kernel_pmap</code>. We have to do this exact thing for all remaining offsets.</p>
<h3 id="adding-the-device-to-the-list">Adding the device to the list</h3>
<p>In my case, Trident already has a structure of type <code class="language-plaintext highlighter-rouge">t_target_environment</code> called <code class="language-plaintext highlighter-rouge">info_to_target_environment</code>. My device with my iOS Version isn’t part of it so I’ll have to add it manually. My code would look like this.</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">//ofsetfinder.c</span>
<span class="n">t_target_environment</span> <span class="nf">info_to_target_environment</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">device_model</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">system_version</span><span class="p">)</span> <span class="p">{</span>
<span class="n">determineTarget</span><span class="p">(</span><span class="s">"iPhone4,1"</span><span class="p">,</span> <span class="s">"9.0.2"</span><span class="p">,</span> <span class="n">iPhone41_iOS902</span><span class="p">);</span>
<span class="n">determineTarget</span><span class="p">(</span><span class="s">"iPhone4,1"</span><span class="p">,</span> <span class="s">"9.1"</span><span class="p">,</span> <span class="n">iPhone41_iOS910</span><span class="p">);</span>
<span class="c1">//.........</span>
<span class="n">determineTarget</span><span class="p">(</span><span class="s">"iPod5,1"</span><span class="p">,</span> <span class="s">"8.4.1"</span><span class="p">,</span> <span class="n">iPhone51_iOS841</span><span class="p">);</span>
<span class="c1">//I add my device with its iOS version at the end of the list provided by Trident.</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Of course, now I also have to navigate to the header file, <code class="language-plaintext highlighter-rouge">offsetfinder.h</code>, and modify the <code class="language-plaintext highlighter-rouge">enum</code> to contain my device with my iOS version too. Here’s the code.</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">//offsetfinder.h</span>
<span class="k">typedef</span> <span class="k">enum</span> <span class="p">{</span>
<span class="n">NotSupported</span><span class="p">,</span>
<span class="n">iPhone41_iOS902</span><span class="p">,</span>
<span class="n">iPhone41_iOS910</span><span class="p">,</span>
<span class="n">iPhone41_iOS920</span><span class="p">,</span>
<span class="n">iPhone41_iOS921</span><span class="p">,</span>
<span class="n">iPad36_iOS933</span><span class="p">,</span>
<span class="n">iPod51_iOS933</span><span class="p">,</span>
<span class="n">iPod51_iOS934</span><span class="p">,</span>
<span class="c1">//......</span>
<span class="n">iPod51_iOS841</span>
<span class="c1">//I add my device at the end of the enum.</span>
<span class="p">}</span> <span class="n">t_target_environment</span><span class="p">;</span>
</code></pre></div></div>
<p>Trident uses the right offset for the right device by using a <code class="language-plaintext highlighter-rouge">switch</code> case for each device, returning the right offset for the device detected at run-time. Each function for which we need offsets has a <code class="language-plaintext highlighter-rouge">switch</code> for each device on each supported version, so we will have to follow the type if we use Trident, but first we need to find an offset.</p>
<h3 id="finding-the-offsets">Finding the offsets</h3>
<p>So now that we know which offsets we need, it’s time to get them.
Let’s begin with <code class="language-plaintext highlighter-rouge">OSSerializer::serialize</code>. For this, the method is pretty simple. Just search for <code class="language-plaintext highlighter-rouge">__ZNK12OSSerializer9serializeEP11OSSerialize</code>. After some searching, Hopper or IDA will drop you into a function with that name. The address of the first instruction in the function i s<code class="language-plaintext highlighter-rouge">802d5a1c</code> and the assembly line is <code class="language-plaintext highlighter-rouge">802d5a1c ldr r3, [r0, #0x8]</code>. Put your mouse cursor after the address and somewhere on the bottom of the window, Hopper and IDA should tell you the offset. In my case, the offset I am looking for is <code class="language-plaintext highlighter-rouge">0x2d4a1c</code>. That’s the offset we need for <code class="language-plaintext highlighter-rouge">uint32_t find_OSSerializer_serialize(void);</code> in <code class="language-plaintext highlighter-rouge">Trident</code>.</p>
<p>In order to add this offset to <code class="language-plaintext highlighter-rouge">Trident</code>, I’ll navigate to the <code class="language-plaintext highlighter-rouge">offsetfinder.c</code>, locate the <code class="language-plaintext highlighter-rouge">uint32_t find_OSSerializer_serialize(void);</code> and add my device with the right iOS version and the corresponding offset at the end of the switch case. The code looks like this.</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">//offsetfinder.c</span>
<span class="kt">uint32_t</span> <span class="nf">find_OSSerializer_serialize</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="p">{</span>
<span class="k">switch</span> <span class="p">(</span><span class="n">target_environment</span><span class="p">)</span> <span class="p">{</span>
<span class="k">case</span> <span class="n">iPhone41_iOS902</span><span class="p">:</span> <span class="k">return</span> <span class="mh">0x317de4</span><span class="p">;</span>
<span class="k">case</span> <span class="n">iPhone41_iOS910</span><span class="p">:</span> <span class="k">return</span> <span class="mh">0x319450</span><span class="p">;</span>
<span class="k">case</span> <span class="n">iPhone41_iOS920</span><span class="p">:</span> <span class="k">return</span> <span class="mh">0x3106fc</span><span class="p">;</span>
<span class="c1">//...............</span>
<span class="k">case</span> <span class="n">iPod51_iOS933</span><span class="p">:</span> <span class="k">return</span> <span class="mh">0x318388</span><span class="p">;</span>
<span class="k">case</span> <span class="n">iPod51_iOS934</span><span class="p">:</span> <span class="k">return</span> <span class="mh">0x318388</span><span class="p">;</span>
<span class="k">case</span> <span class="n">iPod51_iOS841</span><span class="p">:</span> <span class="k">return</span> <span class="mh">0x2d4a1c</span><span class="p">;</span> <span class="c1">// My offset</span>
<span class="nl">default:</span> <span class="n">abort</span><span class="p">();</span>
<span class="p">}</span>
</code></pre></div></div>
<p>We’re done with this offset. Time to grab the next one on the list, which happens to be <code class="language-plaintext highlighter-rouge">OSSymbol::getMetaClass</code>. This one is also relatively simple. We need to look for <code class="language-plaintext highlighter-rouge">__ZNK8OSSymbol12getMetaClassEv</code>. The same strategy, you place the coursor after the address of the first instruction inside the function and IDA or Hopper will tell you the offset. In my case, the first instruction and its address are <code class="language-plaintext highlighter-rouge">802d7afc movw r0, #0xd85c </code>, and the offset is <code class="language-plaintext highlighter-rouge">0x2d6afc</code>.</p>
<center> <img src="https://user-images.githubusercontent.com/15067741/39975746-78e04946-56fe-11e8-97f0-51fcb6104ace.png" /></center>
<p>So, now that we have the second offset, we’re going to add it to the <code class="language-plaintext highlighter-rouge">swich</code> of the <code class="language-plaintext highlighter-rouge">uint32_t find_OSSymbol_getMetaClass(void);</code>. The code for the <code class="language-plaintext highlighter-rouge">switch case</code> looks like this.</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">uint32_t</span> <span class="nf">find_OSSymbol_getMetaClass</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="p">{</span>
<span class="k">switch</span> <span class="p">(</span><span class="n">target_environment</span><span class="p">)</span> <span class="p">{</span>
<span class="k">case</span> <span class="n">iPhone41_iOS902</span><span class="p">:</span> <span class="k">return</span> <span class="mh">0x31a5d0</span><span class="p">;</span>
<span class="k">case</span> <span class="n">iPhone41_iOS910</span><span class="p">:</span> <span class="k">return</span> <span class="mh">0x31bc3c</span><span class="p">;</span>
<span class="k">case</span> <span class="n">iPad35_iOS934</span><span class="p">:</span> <span class="k">return</span> <span class="mh">0x3219fc</span><span class="p">;</span>
<span class="c1">//..............................</span>
<span class="k">case</span> <span class="n">iPod51_iOS931</span><span class="p">:</span> <span class="k">return</span> <span class="mh">0x31a934</span><span class="p">;</span>
<span class="k">case</span> <span class="n">iPod51_iOS932</span><span class="p">:</span> <span class="k">return</span> <span class="mh">0x31aa6c</span><span class="p">;</span>
<span class="k">case</span> <span class="n">iPod51_iOS933</span><span class="p">:</span> <span class="k">return</span> <span class="mh">0x31ab90</span><span class="p">;</span>
<span class="k">case</span> <span class="n">iPod51_iOS934</span><span class="p">:</span> <span class="k">return</span> <span class="mh">0x31ab90</span><span class="p">;</span>
<span class="k">case</span> <span class="n">iPod51_iOS841</span><span class="p">:</span> <span class="k">return</span> <span class="mh">0x2d6afc</span><span class="p">;</span> <span class="c1">//I add my offset</span>
<span class="nl">default:</span> <span class="n">abort</span><span class="p">();</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>With that one in place, let’s continue our journey to the next offset which happens to be <code class="language-plaintext highlighter-rouge">calend_gettime</code>. This is a tricky one. There is no function called this way. IDA and Hopper generate a random name for this function so you can’t find it by searching for its name. For this, I found an interesting method. May not be the best, and I am pretty sure there are better ways but this worked for me. Search for <code class="language-plaintext highlighter-rouge">_clock_get_uptime</code>. Once you reach this function, count down 5 functions and the 6th function is the one you’re looking for. You know you found it because it has something like this <code class="language-plaintext highlighter-rouge">8001e0ac bl _clock_get_calendar_nanotime</code>. The same method put the cursor after the address of the first instruction in the function prologue and get the offset, which in my case is <code class="language-plaintext highlighter-rouge">0x1d0a0</code>.</p>
<p>And with this, we’ve just obtained the third offset. Now we have to add it to its proper place in the <code class="language-plaintext highlighter-rouge">uint32_t find_calend_gettime(void);</code>. I won’t repeat the same thing, but you got the idea on how you find offsets in the kernel.</p>
<h3 id="bottom-line">Bottom Line</h3>
<p>While different exploits require different offsets, most exploits come with a set of offsets for the device and the iOS version on which the researcher tested the exploit. If no instructions are given on how you can find the correct offsets for your device, it suffices to download the Kernel for the iOS version and the device for which the researcher provided offsets and you can use the given offsets to reverse-engineer the methods used to find them, then you can apply these methods to your own device & iOS version.</p>
<p>I am pretty sure there are better ways to find these offsets, especially if these better methods are scripts :P but I still think this write-up will help more beginners like me to understand where these offsets come and how are they obtained.</p>
<h3 id="references-and-resources">References and Resources</h3>
<ul>
<li>Trident https://github.com/benjamin-42/Trident</li>
<li>Firmware Keys https://www.theiphonewiki.com/wiki/Firmware_Keys</li>
<li>Xpwntool https://github.com/planetbeing/xpwn</li>
<li>PZB https://github.com/tihmstar/partialZipBrowser</li>
<li>Hopper Disassembler https://www.hopperapp.com/</li>
</ul>This write-up uses as an example the Trident project by benjamin-42. The offsets are for the components this particular project requires, but the methodology and the information can easily be adapted to other iOS versions, devices, and projects. Each exploit requires a different set of offsets for various kernel components and each offset is found in a different way, but I believe this information should be useful for beginners. I am gonna use the iPod Touch 5th Generation for this write-up.Having Fun With Arduino’s Memory2018-04-21T00:00:00+00:002018-04-21T00:00:00+00:00https://geosn0w.github.io/Having-Fun-With-Arduino's-Memory<p>Hello everyone, GeoSn0w here! There are times when you need to take a closer look at the address space of your Arduino development board.
Small sketches may or may not render memory problems depending on the Arduino board you’ve got, but a fairly complex project can
easily chew through the SRAM available and multiple allocations and deallocations using <code class="language-plaintext highlighter-rouge">malloc()</code> and <code class="language-plaintext highlighter-rouge">free()</code> may result in
memory issues because the available free chunks may not be big enough to hold what you’re about to allocate.</p>
<p>In situations like these, it’s recommended to keep an eye on the memory, the way data is positioned, and how you can optimize it.</p>
<h3 id="a-matter-of-memory">A matter of memory</h3>
<p>As you probably know, Arduino boards, especially the <code class="language-plaintext highlighter-rouge">AVR</code> ones, don’t come with an awful lot of memory. They’re intended for relatively small projects (or very well optimized ones - that’s the beauty of working that close to the hardware). To better illustrate the memory problems that can occur, I’ve composed the following table containing the built-in SRAM, EEPROM, Flash and the architecture of
the most common Arduino boards.</p>
<p align="center">
<img src="https://raw.githubusercontent.com/GeoSn0w/geosn0w.github.io/master/images/arduino.png" />
</p>
<h3 id="playing-around">Playing around</h3>
<p>Now that is clear that Arduino’s SRAM is nowhere near enough for beefy projects, let’s see how we can peek into it, optimize it and have fun with it. This may be obvious for some people, but just in case, when talking Arduino (especially the lower-end models with less than 4 KB of SRAM), you should avoid excessively using <code class="language-plaintext highlighter-rouge">malloc()</code> and <code class="language-plaintext highlighter-rouge">free()</code>. It’s usually better (of course, if possible) to avoid dynamic memory allocation on Arduino because if the sketch is big enough, after enough allocations and deallocations, the memory will become fragmented and further allocations may fail because there is not enough memory available. Thing is, there might still be enough memory but not grouped in free chunk big enough for the allocation to proceed.</p>
<p>I know that this whole memory concept may sound confusing for the beginners, so I’ll try to build a diagram that should be able to demonstrate how this phenomenon occurs.</p>
<p align="center">
<img src="https://raw.githubusercontent.com/GeoSn0w/geosn0w.github.io/master/images/memory%20segmentation%20on%20arduino.png" />
</p>
<p>As you can see, multiple allocations and deallocations can result in free chunks in between allocated chunks. These free chunks can still be used if what you want to allocate is smaller or equal to the size of the free chunk. If it is bigger, the allocation will seek a bigger free chunk. In our diagram, that’d be in the right corner right after the 3rd allocated block, but if we allocate and deallocate a bit more, it will quickly build free chunks that may not be big enough, therefore, making the allocation to fail.</p>
<h3 id="what-can-you-do">What can you do?</h3>
<p>Depending on what kind of project you want to create, you may find the following good practices useful.
If you are working with strings (<code class="language-plaintext highlighter-rouge">char arrays</code>), you may wanna use the <code class="language-plaintext highlighter-rouge">F()</code> macro. To do that you transform your code from:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">setup</span><span class="p">(){</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">print</span><span class="p">(</span><span class="s">"Hello my name is George and I like to code."</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Into:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">setup</span><span class="p">(){</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">print</span><span class="p">(</span><span class="n">F</span><span class="p">(</span><span class="s">"Hello my name is George and I like to code."</span><span class="p">));</span>
<span class="p">}</span>
</code></pre></div></div>
<p>The <code class="language-plaintext highlighter-rouge">F()</code> macro pretty much puts your string on the Flash (code space) instead of putting it on the SRAM. The amount of flash your Arduino has is bigger than the amount of SRAM so that makes total sense. The way <code class="language-plaintext highlighter-rouge">F()</code> does that is quite complex but I will try to summarize it. I will take for this example the Arduino Mega 2560 which is <code class="language-plaintext highlighter-rouge">AVR</code> architecture. The <code class="language-plaintext highlighter-rouge">AVR</code> architecture is a Harvard Architecture and therefore, the <code class="language-plaintext highlighter-rouge">code</code> and the <code class="language-plaintext highlighter-rouge">data</code> are stored separately. Normally, when you call functions like <code class="language-plaintext highlighter-rouge">print()</code> or <code class="language-plaintext highlighter-rouge">Serial.print()</code> you pass a <code class="language-plaintext highlighter-rouge">char*</code> (Character Pointer) to them. This is pretty much the beginning (base) address of the character array holding your string on the flash. However, there is a problem. As you can see, <code class="language-plaintext highlighter-rouge">char*</code> is a pointer. In order to use whatever the pointer points to, you need to dereference it. When you dereference the pointer it will attempt to return the character stored in the SRAM (Data Space) instead of Flash (Code Space). What <code class="language-plaintext highlighter-rouge">F()</code> does is to pass a <code class="language-plaintext highlighter-rouge">__FlashStringHelper*</code> instead of a <code class="language-plaintext highlighter-rouge">char*</code>, this way pointing the function to the correct location (the code space).</p>
<p>This saves you quite a lot of memory. You can actually test this yourself. If you have an Arduino UNO, try creating 5-6 <code class="language-plaintext highlighter-rouge">character arrays</code> and hold a medium size sentence in each of them. You will see how much memory it chews. After that, use the <code class="language-plaintext highlighter-rouge">F()</code> macro and spot the difference.</p>
<p>Keep in mind that once you put your Data on the <code class="language-plaintext highlighter-rouge">Flash</code>, you can’t modify it at run-time. This is only recommended if the data is constant.</p>
<p>Another good tip for memory optimization is to take advantage of the <code class="language-plaintext highlighter-rouge">PROGMEM</code> for your constants. If you have a lot of constants the <code class="language-plaintext highlighter-rouge">PROGMEM</code> does wonders as it prevents the data declared in it from being copied into the SRAM at boot-time.
All you need to do is to include the correct header:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include <avr/pgmspace.h>
</span></code></pre></div></div>
<p>And use it:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">const</span> <span class="kt">char</span> <span class="n">hello</span><span class="p">[]</span> <span class="n">PROGMEM</span> <span class="o">=</span> <span class="p">{</span><span class="s">"My name is George and I like to code Arduinos"</span><span class="p">};</span>
</code></pre></div></div>
<p>The official <a href="https://www.arduino.cc/reference/en/language/variables/utilities/progmem/"> Arduino Documentation </a> is pretty useful if you want to get started with <code class="language-plaintext highlighter-rouge">PROGMEM</code> for your constants.</p>
<h3 id="maybe-get-into-local-variables">Maybe get into local variables?</h3>
<p>Let’s assume this code:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="n">begin</span> <span class="o">=</span> <span class="mi">64</span><span class="p">;</span>
<span class="kt">void</span> <span class="nf">printNumbers</span><span class="p">(</span><span class="kt">int</span> <span class="n">beginNo</span><span class="p">){</span>
<span class="kt">int</span> <span class="n">firstNumber</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span>
<span class="kt">int</span> <span class="n">secondNumber</span> <span class="o">=</span> <span class="mi">45</span><span class="p">;</span>
<span class="kt">float</span> <span class="n">thirdNumber</span> <span class="o">=</span> <span class="mi">4</span><span class="p">.</span><span class="mi">43</span><span class="p">;</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">print</span><span class="p">(</span><span class="n">firstNumber</span><span class="p">);</span>
<span class="p">}</span>
<span class="n">setup</span><span class="p">(){</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">begin</span><span class="p">(</span><span class="mi">9600</span><span class="p">);</span>
<span class="n">printNumbers</span><span class="p">(</span><span class="n">begin</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>
<p>When you call a function, for example <code class="language-plaintext highlighter-rouge">printNumbers(int beginNo)</code>, the function creates its own <code class="language-plaintext highlighter-rouge">Stack Frame</code>. What does it contain? Well, everything you pass to the function (its parameters) and all local variables that are declared within the function’s scope. This makes the <code class="language-plaintext highlighter-rouge">Stack</code> to grow towards the <code class="language-plaintext highlighter-rouge">Heap</code>. What is declared inside the function can only be used inside the scope of that function. This means that an external function will not be able to use any of the integers or the float we’ve declared inside the function. These variables will only live as long as the function is alive. Once the function finishes, its <code class="language-plaintext highlighter-rouge">stack frame</code> is <code class="language-plaintext highlighter-rouge">popped</code> off the stack and the entire space utilized by the function and its variables is reclaimed (the stack shrinks).</p>
<p>There is still a problem. If you grow your stack too much towards the heap, you run the risk of smashing them one in the other so be careful. Don’t build useless variables that don’t get used.</p>
<p>To help illustrate the memory map and how the <code class="language-plaintext highlighter-rouge">Stack</code> and the <code class="language-plaintext highlighter-rouge">Heap</code> look like, I’ve built yet another diagram.</p>
<p align="center">
<img src="https://raw.githubusercontent.com/GeoSn0w/geosn0w.github.io/master/images/memmap.png" />
</p>
<h3 id="obtaining-the-address-of-a-variable-in-the-memory">Obtaining the address of a variable in the memory</h3>
<p>Arduino, like all other systems, puts each variable at its specific address in the memory so that it can be retrieved and used when needed. The addresses are represented in hexadecimal numbers prefixed by <code class="language-plaintext highlighter-rouge">0x</code>. For example: <code class="language-plaintext highlighter-rouge">0x21D8</code> is currently the address of a variable I’ve created. On systems like your computer, your phone, your tablet, etc. most operating systems use a concept called <code class="language-plaintext highlighter-rouge">ASLR</code> or Address Space Layout Randomization. This concept pretty much puts the data and the code segments at different locations in the memory every time you power on the device or every time you start the program. By randomizing the addresses where the stuff can be found in the memory, a protection layer is implemented. The idea is that the harder is for a hacker to find what he wants to hack in the memory, the more time and the more knowledge it would take to hack the system. Of course, that’s in theory. In real life, <code class="language-plaintext highlighter-rouge">ASLR</code> can easily be defeated by provoking an <code class="language-plaintext highlighter-rouge">info leak</code>. It’s enough to be able to leak a pointer in order to be able to calculate the <code class="language-plaintext highlighter-rouge">ASLR Slide</code> and with that, the randomized position of each function, variable, etc. you wanna patch in memory.</p>
<p>Kernels like <code class="language-plaintext highlighter-rouge">XNU</code>, the Linux Kernel, Windows Kernel, and so on also implement this at boot-time (usually from the <code class="language-plaintext highlighter-rouge">bootloader</code> side) but it is called <code class="language-plaintext highlighter-rouge">kASLR</code> or Kernel Address Space Layout Randomization. The same theory applies. The whole kernel is randomized in the memory to prevent the hacker from knowing where in the memory is the function he wants to hack. Leak a <code class="language-plaintext highlighter-rouge">Kernel Pointer</code> and calculate the <code class="language-plaintext highlighter-rouge">slide</code>, use a disassembler like Hopper, Radare2 or IDA Pro to gather the unslid address of the function you’re interested in, and you’ve defeated KASLR.</p>
<p>Arduino doesn’t implement ASLR. The address space isn’t randomized here, but the location of your variables will change from a project flashing to another.</p>
<p>On Arduino, the easiest way to obtain the address of a variable or a function in the memory is to take advantage of the pointers. Let’s assume this code:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="nf">helloWorldFunction</span><span class="p">(){</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">print</span><span class="p">(</span><span class="s">"Hello world"</span><span class="p">);</span>
<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">int</span> <span class="nf">getAddressOfFunction</span><span class="p">(){</span>
<span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">functionPointer</span><span class="p">)(</span><span class="kt">void</span><span class="p">)</span> <span class="o">=</span> <span class="o">&</span><span class="n">helloWorldFunction</span><span class="p">;</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">print</span><span class="p">(</span><span class="s">"The address of the helloWorldFunction() is 0x"</span><span class="p">);</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">print</span><span class="p">(</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span> <span class="n">functionPointer</span><span class="p">,</span><span class="n">HEX</span><span class="p">);</span>
<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">setup</span><span class="p">(){</span>
<span class="n">Serialbegin</span><span class="p">(</span><span class="mi">9600</span><span class="p">);</span>
<span class="n">helloWorldFunction</span><span class="p">();</span>
<span class="n">getAddressOfFunction</span><span class="p">();</span>
<span class="p">}</span>
</code></pre></div></div>
<p>This code will hapily print the address where the function <code class="language-plaintext highlighter-rouge">helloWorldFunction</code> resides in the memory. To get the address, we use the <code class="language-plaintext highlighter-rouge">&</code> operator. The pointer can point to a function that returns an <code class="language-plaintext highlighter-rouge">int</code> and has no parameters <code class="language-plaintext highlighter-rouge">(void)</code> passed to it. We also need to cast the pointer to <code class="language-plaintext highlighter-rouge">int</code> by doing <code class="language-plaintext highlighter-rouge">(int) functionPointer</code> when we print it. Finally, the <code class="language-plaintext highlighter-rouge">HEX</code> means that we want to print the address in hexadecimal format.</p>
<h3 id="peeking-into-the-memory">Peeking into the memory</h3>
<p>If you want to obtain the address of the Stack Pointer and the Heap Pointer, it’s pretty simple.
Let’s assume this code:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">uint8_t</span> <span class="o">*</span> <span class="n">HeapPointer</span><span class="p">,</span> <span class="o">*</span> <span class="n">StackPointer</span><span class="p">;</span> <span class="c1">// Globally declaring the Stack and Heap pointers.</span>
<span class="kt">int</span> <span class="nf">getPointers</span><span class="p">(){</span>
<span class="n">StackPointer</span> <span class="o">=</span> <span class="p">(</span><span class="kt">uint8_t</span> <span class="o">*</span><span class="p">)</span><span class="n">malloc</span><span class="p">(</span><span class="mi">4</span><span class="p">);</span> <span class="c1">//We do a small allocation.</span>
<span class="n">HeapPointer</span> <span class="o">=</span> <span class="n">StackPointer</span><span class="p">;</span> <span class="c1">// We save the value of the heap pointer.</span>
<span class="n">free</span><span class="p">(</span><span class="n">StackPointer</span><span class="p">);</span> <span class="c1">// We use the dreaded free() to zero the StackPointer.</span>
<span class="n">StackPointer</span> <span class="o">=</span> <span class="p">(</span><span class="kt">uint8_t</span> <span class="o">*</span><span class="p">)(</span><span class="n">SP</span><span class="p">);</span> <span class="c1">//Get the Stack Pointer</span>
<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">setup</span><span class="p">(){</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">begin</span><span class="p">(</span><span class="mi">9600</span><span class="p">);</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">print</span><span class="p">(</span><span class="s">"0x"</span><span class="p">);</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">print</span><span class="p">((</span><span class="kt">int</span><span class="p">)</span> <span class="n">StackPointer</span><span class="p">,</span> <span class="n">HEX</span><span class="p">);</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">print</span><span class="p">(</span><span class="s">"0x"</span><span class="p">);</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">print</span><span class="p">((</span><span class="kt">int</span><span class="p">)</span> <span class="n">HeapPointer</span><span class="p">,</span> <span class="n">HEX</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>
<p>The following code should happily print the <code class="language-plaintext highlighter-rouge">Stack Pointer</code> and the <code class="language-plaintext highlighter-rouge">Heap Pointer</code>. The code is inspired from the Arduino Forums (with some personal modifications).
I hope this write-up helps. Took me a while to put it together but I hope it will come in handy for somebody some day.</p>Hello everyone, GeoSn0w here! There are times when you need to take a closer look at the address space of your Arduino development board. Small sketches may or may not render memory problems depending on the Arduino board you’ve got, but a fairly complex project can easily chew through the SRAM available and multiple allocations and deallocations using malloc() and free() may result in memory issues because the available free chunks may not be big enough to hold what you’re about to allocate.How to implement program arguments and how they are parsed in C/C++2018-04-07T00:00:00+00:002018-04-07T00:00:00+00:00https://geosn0w.github.io/Arguments-in-C-CPP<p>C and C++ offer a big level of freedom to the programmer. That is efficiently dangerous, as the programmer has to know what he is doing.
Computers are deterministic machines. They do what they are told to do, and if what they’re told is wrong, they will most likely
proceed anyways. While C and C++ compilers do warn programmers and in some cases even refuse to compile, that only happens if the grammar errors (as in programming language grammar) are found.
Don’t expect the compiler to try to guess what you try to do. It will assume you know what you try to implement and will not check your code logic for anything other than grammar errors or type errors.
In this post, I will go to the lengths of how you can implement arguments in your program and how they work.</p>
<h6 id="implementation">Implementation</h6>
<p>You may scratch your head saying “gee, what has that abstract to do with the topic?”. Well, as the compiler assumes you know what you are doing, it will also assume you programmed whatever functions you need.
By default, starting a program <code class="language-plaintext highlighter-rouge">program</code> with the arguments <code class="language-plaintext highlighter-rouge">-debug -toFile</code> will do absolutely nothing to the program because a computer is a deterministic machine and it will not implement argument parsing in your program for you.
And even when you do remember that all the functions in a program must be created by a programmer, you can still fail spectacularly.
Arguments in a program may not seem like a big deal, they’re pretty beginner things, right? right??? guys??</p>
<p>We often implement the <code class="language-plaintext highlighter-rouge">main()</code> function something like this, but why?</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="n">argv</span><span class="p">[]){</span>
<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>What means <code class="language-plaintext highlighter-rouge">argc</code> and why is it an <code class="language-plaintext highlighter-rouge">int</code>? What means <code class="language-plaintext highlighter-rouge">argv</code> and why is it a <code class="language-plaintext highlighter-rouge">pointer</code> to a <code class="language-plaintext highlighter-rouge">char array</code>?
See? You may know how to make your program to accept arguments at load-time but you don’t know the inner workings.</p>
<p><code class="language-plaintext highlighter-rouge">argc</code> is a name we give to <code class="language-plaintext highlighter-rouge">argument counter</code>, while <code class="language-plaintext highlighter-rouge">argv</code> stands for <code class="language-plaintext highlighter-rouge">argument list</code> otherwise known as <code class="language-plaintext highlighter-rouge">argument vector</code>.</p>
<p>The reason we need to keep track of how many arguments the user has passed to the program becomes visible when you begin to understand that to a computer, your program is nothing but memory addresses containing stuff. At some point in the life of your program, you want to do something with the arguments the user has supplied, being that a check, a comparison or anything else.
To do that, you parse let’s say the <code class="language-plaintext highlighter-rouge">3rd array element</code> from the <code class="language-plaintext highlighter-rouge">argv</code> which is the <code class="language-plaintext highlighter-rouge">char array</code> in which the user supplied arguments are being stored. Naturally, that array is located at a memory address within the bounds of your program. The problem will become visible in a second.</p>
<p>Let’s assume:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include <stdio.h>
#include <stdlib.h> //for exit()
</span>
<span class="kt">void</span> <span class="nf">howtoUse</span><span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="n">ourProgram</span><span class="p">){</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"Usage: %s, <your name> <your age></span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">ourProgram</span><span class="p">);</span>
<span class="n">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span> <span class="c1">//Terminate the program</span>
<span class="p">}</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="n">argv</span><span class="p">[]){</span>
<span class="c1">//Begin of safety check</span>
<span class="k">if</span> <span class="p">(</span><span class="n">argc</span> <span class="o"><</span> <span class="mi">3</span><span class="p">){</span> <span class="c1">//If the user supplied fewer arguments than we need...</span>
<span class="n">howtoUse</span><span class="p">(</span><span class="n">argv</span><span class="p">[</span><span class="mi">0</span><span class="p">]);</span> <span class="c1">//We pass the program name as argument 0.</span>
<span class="p">}</span>
<span class="c1">//End of safety check</span>
<span class="kt">int</span> <span class="n">age</span> <span class="o">=</span> <span class="n">atoi</span><span class="p">(</span><span class="n">argv</span><span class="p">[</span><span class="mi">2</span><span class="p">]);</span> <span class="c1">//ASCII to INTEGER (atoi).</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"Your name is %s and you are %d years old.</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">age</span><span class="p">);</span>
<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Ok, so this is a simple program I wrote. It will accept two arguments: a name and a number for the age.
Naturally, we start the program with the required arguments:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>MacBook-Pro-van-Mac:~ mac$ /Users/mac/Desktop/file George 29
Your name is George and you are 29 years old.
MacBook-Pro-van-Mac:~ mac$
</code></pre></div></div>
<p>This is exactly the expected behavior.
We got the arguments and we used them during the life of the program.
What happens if the user forgets to supply the arguments? Or an argument? Or a space between arguments? Or too many arguments?
Well, since we do have a safety check based on comparing <code class="language-plaintext highlighter-rouge">argc</code> with the number of arguments we should have (3) we can stop an error.</p>
<p>Wait! Why 3 arguments? We ask only for 2!?
Well, not really. <code class="language-plaintext highlighter-rouge">argv[0]</code> will always be the name of the program and the user-supplied arguments start from <code class="language-plaintext highlighter-rouge">argv[1]</code>. 2 user-supplied arguments and argument 0 which is the program name result in 3 total arguments in the <code class="language-plaintext highlighter-rouge">char array</code>.</p>
<p>Let’s see what happens if we only supply one argument:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>MacBook-Pro-van-Mac:~ mac$ /Users/mac/Desktop/file George
Usage: /Users/mac/Desktop/file, <your name> <your age>
MacBook-Pro-van-Mac:~ mac$
</code></pre></div></div>
<p>Naturally, our small <code class="language-plaintext highlighter-rouge">if()</code> check saved the program from crashing into oblivion and let it safely quit.
Let’s remove the safety check – ooh, dangerous :P</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include <stdio.h>
#include <stdlib.h> //for exit()
</span>
<span class="kt">void</span> <span class="nf">howtoUse</span><span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="n">ourProgram</span><span class="p">){</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"Usage: %s, <your name> <your age></span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">ourProgram</span><span class="p">);</span>
<span class="n">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span> <span class="c1">//Terminate the program</span>
<span class="p">}</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="n">argv</span><span class="p">[]){</span>
<span class="c1">//No safety check. This is sooo gonna crash.</span>
<span class="kt">int</span> <span class="n">age</span> <span class="o">=</span> <span class="n">atoi</span><span class="p">(</span><span class="n">argv</span><span class="p">[</span><span class="mi">2</span><span class="p">]);</span> <span class="c1">//ASCII to INTEGER (atoi).</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"Your name is %s and you are %d years old.</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">age</span><span class="p">);</span>
<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>The program will still operate normally while the required number of arguments are supplied, however, once the user makes a mistake, it will take the program with it.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>MacBook-Pro-van-Mac:~ mac$ /Users/mac/Desktop/file George
Segmentation fault: 11
MacBook-Pro-van-Mac:~ mac$
</code></pre></div></div>
<p>Sure enough, our program crashed into oblivion with a darn <code class="language-plaintext highlighter-rouge">SEGFAULT</code>.
A <code class="language-plaintext highlighter-rouge">SEGFAULT</code> means your program tries to access a memory region it is not supposed to access. The memory is split into segments, your program has access to some given segments and it will work just fine. Once it tries to read/write to segments it has no access to (beyond the boundaries), it will crash.</p>
<p>Let’s see what happened through the magic of a debugger, shall we?</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>MacBook-Pro-van-Mac:~ mac$ sudo gdb -q ./a.out
Reading symbols from ./a.out...Reading symbols from /Users/mac/a.out.dSYM/Contents/Resources/DWARF/a.out...done.
done.
(gdb) run George
Starting program: /Users/mac/a.out George
Program received signal SIGSEGV, Segmentation fault.
0x00007fff9f6fb48b in strtol_l () from /usr/lib/system/libsystem_c.dylib
(gdb) break main
Breakpoint 1 at 0x100000ee6: file /Users/mac/Desktop/file.c, line 11.
(gdb) run George
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /Users/mac/a.out George
Breakpoint 1, main (argc=2, argv=0x7fff5fbffca0) at /Users/mac/Desktop/file.c:11
11 int age = atoi(argv[2]); //ASCII to INTEGER (atoi).
(gdb) info registers
rax 0x100000ed0 4294971088
rbx 0x0 0
rcx 0x7fff5fbffd58 140734799805784
rdx 0x7fff5fbffcb8 140734799805624
rsi 0x7fff5fbffca0 140734799805600
rdi 0x2 2
rbp 0x7fff5fbffc80 0x7fff5fbffc80
rsp 0x7fff5fbffc60 0x7fff5fbffc60
r8 0x0 0
r9 0x7fff7e0a20c8 140735307981000
r10 0xffffffff 4294967295
r11 0xffffffff00000000 -4294967296
r12 0x0 0
r13 0x0 0
r14 0x0 0
r15 0x0 0
rip 0x100000ee6 0x100000ee6 <main+22>
eflags 0x206 [ PF IF ]
cs 0x2b 43
ss <unavailable>
ds <unavailable>
es <unavailable>
fs 0x0 0
---Type <return> to continue, or q <return> to quit---
gs 0x0 0
(gdb) cont
Continuing.
Program received signal SIGSEGV, Segmentation fault.
0x00007fff9f6fb48b in strtol_l () from /usr/lib/system/libsystem_c.dylib
</code></pre></div></div>
<p>It becomes quite clear that our program went a bit overboard. Without proper checks on the arguments, when our program tries to work with that variable it will try to access an address to a chunk of memory it has never been granted permission to put stuff in, and will, therefore, crash spectacularly.</p>
<p>I hope this write-up helps future programmers. Have fun and always check user input! NEVER trust user input.</p>C and C++ offer a big level of freedom to the programmer. That is efficiently dangerous, as the programmer has to know what he is doing. Computers are deterministic machines. They do what they are told to do, and if what they’re told is wrong, they will most likely proceed anyways. While C and C++ compilers do warn programmers and in some cases even refuse to compile, that only happens if the grammar errors (as in programming language grammar) are found. Don’t expect the compiler to try to guess what you try to do. It will assume you know what you try to implement and will not check your code logic for anything other than grammar errors or type errors. In this post, I will go to the lengths of how you can implement arguments in your program and how they work.