Ludum Dare 43 Post Mortem

I’ll do my best to keep all my disappointment out of this post but I am obviously a little upset that after 27+ hours of work I didn’t have a game to deliver. I think there’s tons to take away from the entire experience even though technical tooling issues became too much to handle at the end.. Because after all that work I did make something that I was able to have some fun with.. even if I couldn’t share it like I was hoping to :/

What Ended Everything

I don’t think it’s fair to blame all my problems on a single extension but I will say that it was not smart on my part to try and use something I had never used full cycle (dev w/ git -> deliverable .exe / HTML package).. I’m usually not the one to buy into the marketing hype but I was sold as soon as I saw this gif
I saw that late one night and ended up pulling the trigger right before the Jam started.. Not testing the tool (GMLive) adequately before jumping into a competition was a mistake.. should have / could have used a day before the Jam to create a small project that I had tested the creation of an .exe + HTML package In the end I’ve created a post on the itch.io page for the GMLive project in case my issue might be something larger (can contribute to the project) / obvious that I shouldn’tve done during development. After 3 days in the weeds, hunting down a bug that only exists when the extension I was using was turned off.. was enough for me to throw in the towel with < 3 hours left (I’m editing this post a day after the event and have spend 1-2 hours doing further debugging without any luck.. will get it eventually…1 week later still haven’t had the heart to hunt it down)

Theme Ideation

Had an idea pretty early on that a tower climb card game w/ small deck size + hard choices after each level (choose 1/3 cards to add to your deck but others are given to next level boss) would be something that I’d like to build. Main “interesting” gameplay mechanic was cards you passed on (being used be subsequent enemies) would get upgraded during harder levels making your decisions to “sacrifice cards to the tower” that much harder and more important during the actual gameplay.
Personal goal was to deliver 4/5 levels of increasing difficulty that would build/introduce card mechanics.. playing MTG since I was little this felt like something I wanted to take on and was up for (no matter the challenges of balance, design, etc)
Overall I was pleased with the theme and happy that I came up with an idea and stuck to it (still believe gameplay/general idea would have been enjoyable)

Wasted Time

Looking back at the time-lapse video + commits throughout the event its pretty clear that I got ahead of myself on the art side of the project. I don’t think it was a smart call to start messing with any artistic tweaks before multiple levels were built + tested in .exe/HTML versions (always problems). Of course hindsight is 20-20 but the LD before my mantra was “Don t waste time play testing or trying to be an artist”. Unfortunately I think I did both.. too excited about making a card game + distracted by the fact I made something pretty on accident Should honestly write the mantra on a whiteboard in my room before the Jam starts.. creating cool looking shit is great but that’s really not me.. should get help on that front in the future if I want things to look pretty..

Custom IDE Experience

I’ve been working on a custom IDE / GM Studio companion application to allow me to edit / compile my projects outside of GM. I’d say that 95% of the time I was using my IDE and the other 5% was spent dealing with GM Studio complaining about memory access issues + strangeness with accidentally creating 2 scripts with the same name or having an object deleted but project.gmx file not being updated I will definitely be making stylistic changes to the IDE (was not built for multiple resolution so using on a laptop was pretty silly) to increase usability + functionality when editing larger projects; had initially shrugged off implementing proper TreeView structure for objects/scripts in “Groups” since the directory structure was “good enough”.. turns out it would have been nice to use and abuse groups and the project grew.. IDE did not handle that and was not going to swap to C# mid Jam and implement XML parsing In the end the ghetto solution I’ve got pre-Github roll up is workable and was enjoyable to use during the Jam but is very much incomplete in terms of the full fledged experience I was hoping for. Big things to knockout in the future are; (1) changes in IDE look the same as changes in GM (num spaces / tabs?), (2) usability changes for viewing in different resolutions / allow the frame to be adjusted as needed (found myself just wanting to click through scripts and read contents within the IDE.. dynamic “Inspect object” section might be nice), (3) Build tree structure from project.gmx file.. this is all GM Studio 1.4.9999 seems to care about so we should do the same (crawling directories was nice + worked but… would avoid lots of headache if the content of that was guaranteed + confirmed by IDE rather than having to open GM to complain about something)

Engine Building

I felt slow during this phase of the compo. Think I should have focused on 2/3 cards only early on and created the basics for gameplay on multiple levels ASAP. When I went to bed not competing the Initial Battle phase that was written on my whiteboard I think I was in a bad spot. Not a terrible spot but definitely not where I should have been (especially if I was on a team.. cant imagine showing up in the morning with a half working engine that looked like shit).. Should have pushed harder for that base engine / been more focused on limiting the scope of the MVP Because of the things that were taken on unnecessarily early, I think that the battle logic code is all over the place.. right now I’m afraid to look at the code but am certain the logic for battling morphed and morphed into something that was going to be cleanly handled by 1 object into 2 objects juggling responsibilities inside of a STEP function that was probably calling multiple alarms.. Maybe its not that bad… but I think code review post mortem would be a separate post entirely

Takeaway

LDs are awesome and a great way to test yourself! I’m glad I pushed myself to build something that made me uncomfortable (felt like a much larger ask than the text / platform games I usually throw together for these things). While I didn’t turn anything in I’m still sitting on a codebase that I’m hoping will be workable and understandable when I revisit it with a clearer head. I’ll definitely be competing in the next Ludum Dare and will put it on my calendar now so I don’t find out about it a few days before..

Links

Posted in tooling, Uncategorized | Tagged , | Leave a comment

Git Auth when Windows Credentials are Locked / Just want to use file

Most Windows users won’t run into this problem because they don’t have a system administrator controlling their machine but for anyone who is experiencing weirdness while using wincred here’s a brief explanation of the problem + an easy fix to get things back up and running.

The wincred issue that I was facing was anytime I ran powershell as a non-administrator I would be prompted for my Username/Password and rather than it being persisted I would get a fun CredWrite failed error and would be prompted again on each subsequent git related call. At first I was at a total loss and was running everything as an admin just to avoid that annoying prompt when trying to pull/push/etc. I finally decided enough is enough and started doing some digging on how windows creds were being persisted on my machine.

Upon looking up the CredWrite failure it became clear that this was a Windows specific Git credential manager that I was oblivious to. The default storage on Windows is something called wincred, which is essentially a Windows built-in credential manager that can be accessed via Control Panel

Unfortunately for me when I drill into the manage page I get the following

Welp that explains the CredWrite failure I was seeing all over the place. Since I was unable to use the recommended a git-credential-store helper I had to resort to using the store –file option to get things working as I’d expect on any other machine (less than ideal but worth it to not be forced to type my username/password every time I wanted to git)

There are a few options to disable the Git Credential Manager (detailed here) but here’s the method I used to get unblocked:

  • git config –global credential.helper “store –file ~/.gitcredentials”
  • Create gitcredentials file and place my creds in there according to the specified format
username=myuser
password=mypass
  • git config –edit –system
  • Remove the helper = manager line that is still in the system even though we specified to use the file for cred info
  • Celebrate because we can git without being prompted every time!

The main issue I had was that I thought setting the file store in (1) would be enough but still ran into the problem where the cred manager was still being used. Checking the global config is critical to ensure that things are going to work as expected and it’s not a bad idea to know exactly what’s going on at the global level

Posted in git, windows | Leave a comment

Twitter Gaming: Tweepi.com Functionality Rip

There are plenty of twitter management tools out that will help automate / manage your twitter account for a few bucks a month.

While most products don’t add too much value I’ve found some particular features on Tweepi.com that have been pretty helpful. In particular there’s a stat called Follower Ratio which lets you know how likely a user is to follow you back; > 80% is a user thats probably worth following (and unfollowing later once we have a healthy count..will lose some followers from bot automation but majority of real users won’t unfollow back)

When using the free version of the site there is a tool that allows us to search up to 25 users using a comma seperated list. This definitely looks like a tasty target and upon checking the network tab we can see a clean POST with easily understood params and response. A test response is shown below

We can see from the response below that calculating Follower Ratio is as easy as followers_count/friends_count is all we need to process a user object in our script.

POST https://tweepi.com/data/get_users_pp/follow_by_copy_paste.json
....

RESPONSE:
{
   "total":1,
   "page_size":20,
   "users":[
      {
         "user_id":"*****",
         "screen_name":"*************",
         "location":"",
         "full_name":"*************",
         "last_tweet_time":"1969-12-31 16:00:00 -0800", // cute
         "followers_count":1,
         "friends_count":89,
         "statuses_count":0,
         "profile_img_url":"\/\/abs.twimg.com\/sticky\/default_profile_images\/default_profile_normal.png",
         "is_verified":false,
         "utc_offset":null,
         "bio":"it's hi astonishing ocean blue eyes that iadore the most but it's his contagious bright smile that transforms my orrowful frown into something joyous",
         "url":"",
         "lang":"en",
         "is_protected":false,
         "member_since":"2017-09-06 05:02:47 -0700",
         "listed_count":0,
         "favourites_count":0,
         "default_profile":true,
         "default_profile_image":true,
         "geo_enabled":false,
         "ui_last_updated":"2018-01-01 12:36:23 -0800",
         "is_follower":false,
         "is_friend":false,
         "follower_or_following":" ",
         "history_date":"2000-01-01 00:00:00 +0000",
         "is_safelisted":false,
         "tag_names":[

         ],
         "tag_dates":[

         ]
      }
   ]
}

As long as we can replay this request then we should be able to come up with a clever way to “smart follow” with a handy javascript snippet…

Building the Request for Replay

And a little bit of request fiddling as we figure out what headers are necessary we go from..

import requests
response = requests.post("https://tweepi.com/data/get_users_pp/follow_by_copy_paste.json",params={"userSnList":"foo","offset":0,"limit":25}, 
headers={
"X-Authorization": "ZnJlZTpncmlkLmZvbGxvd0J5Q29weVBhc3RlOjk0NjM0Mjg0MzYwMTI0ODI2MQ==",
"X-Requested-With": "angular",
"X-Tab-Id": "7166",
"Content-Type": "application/json;charset=utf-8",
"Accept-Language": "en-US,en;q=0.5",
"Accept": "application/json, text/plain, */*",
"Accept-Encoding": "gzip, deflate, br",
"Cookie": "c111990290-79992ic=c232338-43784-319745; c111990290-280953ic=c232338-43784-574953; tr2=1; tweepiapp=slqi3ldt8upm8oitf17eke44k2; kvcd=1514838972500; km_ai=G8OrOVIF0YFYftSnBsF7Qgi8aoM%3D; km_lv=x; km_vs=1"
})
response.content

to

import requests
response = requests.post("https://tweepi.com/data/get_users_pp/follow_by_copy_paste.json",params={"userSnList":"tonishabusch281","offset":0,"limit":20}, 
headers={
"X-Authorization": "ZnJlZTpncmlkLmZvbGxvd0J5Q29weVBhc3RlOjk0NjM0Mjg0MzYwMTI0ODI2MQ==",
"Cookie": "tr2=1; tweepiapp=slqi3ldt8upm8oitf17eke44k2;"
})
response.content


and we now can have some fun

Creating Twitter User Check List

The first thing is to get a list of potential users that we would want to follow. We can use the follower page from accounts that are well established. Since we don’t want to scroll for days let’s use a simple scroll function that we can turn off / control with the conditional. Once we have all the user nodes loaded we can run the second chunk of code to build a comma seperated user list that we will use in our python script; you’ll notice a copyToClipboard function at the end which allows us to easily select the entire list since console.log is disabled on Twitter and returns will be truncated.

// scroll until we see all users
var count = 0;
function st(){
  $("html, body").animate({ scrollTop: $(document).height() }, "fast");
  if(count < 2000) {
    count += 1;
    setTimeout(st, 500);
  }
}
st()
// then set count=999999

// XXX: done since console.log is taken over.. cute but not going to stop us
// create a div element and append twitter names to it (formatted for copy pasta in script above)
document.body.innerHTML += '<div id="userlist"></div>';
var eles = document.querySelectorAll('b.u-linkComplex-target');
for(var i=4; i<eles.length-5;i++) {
    document.getElementById('userlist').innerHTML += eles[i].innerHTML+',';
}

// console should print out the goodies when exiting the for loop but just in case
// never occured to me that something so simple would do the trick :D
// https://stackoverflow.com/questions/400212/how-do-i-copy-to-the-clipboard-in-javascript
function copyToClipboard(text) {
    window.prompt("Copy to clipboard: Ctrl+C, Enter", text);
}
copyToClipboard(document.getElementById('userlist').innerHTML)

and it works like a charm! 🎉

From there it’s time to use that user list inside a python script that will allow us to slam that endpoint as a free user. Since I don’t have a premium account there’s a limit of 25 users per bulk update, 500 for premium users.. maybe we can get around this somehow… but for now the script does the trick. In addition to updating the list we will most likely need to get a new valid tweepi session which will require us to change the tweepiapp value in the Cookie header.

import requests
import time
import json

def chunks(l, n):
    for i in range(0, len(l), n):
        yield l[i:i + n]

n = "INSERT_COPY_HERE"
names = n.split(',')        
split_names = list(chunks(names, 25))

count = 0
high_prop_users = [] # will use this to store "valuable" users
# XXX: why manage valid array index when you can try catch all the things... terrible terrible terrible but whatever im tired
try:
    while True:
        name_list = ','.join(str(x) for x in split_names[count])
        response = requests.post("https://tweepi.com/data/get_users_pp/follow_by_copy_paste.json",params={"userSnList": name_list,"offset":0,"limit":25}, 
        headers={
            "X-Authorization": "ZnJlZTpncmlkLmZvbGxvd0J5Q29weVBhc3RlOjk0NjM0Mjg0MzYwMTI0ODI2MQ==",
            "Cookie": "tr2=1; tweepiapp=7tk8us7lj933i743l4mos51q10;"
        })
        if '!doctype html' in str(response.content):
            print('TRY AGAIN')
        else:
            parsed_response = json.loads(response.content)
            users_info = parsed_response['users']
            for user in users_info:
                follow_ratio = user['followers_count']/user['friends_count']
                if follow_ratio > 0.8:
                    high_prop_users.append(user['screen_name'])
                    print('INSERTED')
            time.sleep(2)
        print('-----------------------------------------')
except:
    print(high_prop_users)
    exit(0)

Now that we have our final list of users we want to follow we just need another Javascript snippet to properly follow all those users.

Im sure there’s a better way to manage the parent search with jquery but it’s good enough for me / twitter since this is unlikely to change during the usefullness of this script (if it does it wont work and it’ll be an obvious fix). You may notice a strange id assignment at the beginning, this is to ensure that our simple for look can do something like lookup with getElementById and go from that base element to get anything else we might need..

// assign id to twitter handle for easy access using the list we built up
var names = document.querySelectorAll('.u-linkComplex-target')
for(var i=4;i<names.length-5;i++) {
  names[i].id = names[i].innerHTML.trimLeft(); // important to trim the random spacing in the div..
}

// follow everyone in our magic list
st = ['**', ..., '**']
for(var i=0;i<st.length-1;i++) {
    // sitting in console with a beer is definitely the best way to do this..
    $($(document.getElementById(st[i])).parent().parent().parent().parent().siblings()[1]).find('.user-actions-follow-button').click();
}

Using those 2 Javascript snipped and the hacky Python script we can succssfully re-create the functionality that Tweepi wants us to pay $9.99 a month for.

Posted in python, tweepi, twitter | Leave a comment

Bioshock: Infinite Review


The initial introduction to the underwater dystopian society of Rapture in the original Bioshock was something that I recommend every real gamer experience (even if you aren’t an FPS kind of person). The familiar themes of authoritarian rule and dark despair from the previous 2 installments make a return and should be a pleasant reminder of the previous roller coaster rides we’ve taken before.. Nostalgically remembering Atlas… if you don’t get that you should seriously sit down and play the first game (wait for Steam sale and buy all 3 games w/ remastered versions for < $15)

Alright so it’s probably not fair to assume that everyone has played the previous games but luckily the majority of the gameplay doesn’t require any previous series knowledge to enjoy. The change from the enclosed spaces of Rapture to the limitless freedom of the skies of Columbia is a welcome and creative change. The introduction of the Skyhook is the main way to harness some of that open space and feels great when it can be properly utilized in a consequential battle. Unfortunately for all the fun the new mechanics introduced they do get stale pretty quickly and for the most part are completely unnecessary to accomplishing the task of dispatching waves of baddies.. (1)Flying around on a Skyhook loop while you pick off the hordes of enemies slowly without taking a scary amount of damage feels lame just to move on to the next segment. (2) Having Elizabeth’s animation to throw you Ammo/Salts/Health during battle felt amazing the first few times but after learning to exploit the throws; wait till low ammo for toss to maximize shooting time + know she can throw that thing from anywhere (she will teleport for you so don’t stress). For 80% of the game you won’t run into these annoyances (resources are good, no real advantage on Skyhook, no buggy Elizabeth) but it cannot be ignored or missed in a playthrough (maybe I’m the only one that was bothered by this on both my runs of the game).

For the most part the sequenced fights are well planned and force the player to think about cover and how they will use their various Vigors to overcome the reasonable challenge. There are other times when the “ambush” is obviously planned and it feels like you are just doing a dance to kill 3 waves before you can open the next door to do the same thing. While predictable fights and AI funnelling does occur from time to time these occasions are in the minority to the meaningful fights where a pack of Patriots shows up and presents a welcome last annoyance before you can get on a gondola to the next section of Columbia. Combat consists of a combination of using Vigors and guns to dispatch of enemies in whichever way you see fit; I ignored the pistol and leveled up my shotgun, machine guns and sniper while maxing out salts and abusing crows, soul steal and lightning on machines. The option to take combat in whichever direction you want with various Vigor upgrades along with Armor, Health, and Salt upgrades found along the way is well executed and is one of the main reason one would come back for a second / third playthrough. The one gripe I have with the RPG-lite-esque combat system is that the entire clothing upgrades felt entirely pointless to change along the way, juggling the various outfits that gave additional combat effects seemed really awesome but in reality it feels like a cumbersome addition that isn’t even worth paying attention to.

The storyline follows along the lines of a dystopian society that hails a demigod and his family. Playing as Booker DeWitt we are responsible for rescuing the princess from her captures at all costs. Without giving anything away (just in case) our damsel in distress is a young girl named Elizabeth who can open rifts into other dimensions, justifying her isolation and protection by a massive songbird. As you can imagine the story plays with themes of freedom and imprisonment, which is particularly interesting given the idea that Columbia has seceded from the United States right after the abolition and obviously wasn’t too happy with that Lincoln guy. While the story is nothing spectacular it delivers an engaging world that feels worth exploring and trying to better understand through the audio diaries scattered.

In reality when the game is at its best (the majority of the time) it shines bright but there always seems to be some lingering blemish that prevents the game from being a true masterpiece. While I wanted to get lost in the beauty and creativity of the circa 1900 American secessionist city of Columbia, the game constantly trips over itself with the inconsequential mechanic or monotonous fight that tend to feel like nothing more than filler.

Overall a worthwhile experience with a few hiccups that prevent it from being a true classic on its own. Expect a remastered version to be released in a few years.

4/5

Posted in Game Review | Leave a comment

Reverse Engineering ‘Product Catalog’

Recently I’ve been looking at an application that has some data that I’d like to scrape and use/format for my own selfish desires. The application we are targeting is on iOS + Android so I went through the usual flow on my iPhone
– mitmproxy – no good. traffic must be SSL / non-HTTP. Android cert-pinning stops app on init
– wireshark w/ rvictl on iOS device – SSL traffic pulling initial data catalog / no API fetches once app is initialized (sqlite init)

After getting blocked and giving up for about a month I decided to root my OG Nvidia Shield and dig a little deeper..

Digging Deeper

Prereqs

Root phone -> Install Xposed Framework -> Download [Inspeckage] Module -> Get Started

My initial hope was that Inspeckage would solve all my problems and I wouldnt have to dig too much into Xposed but in the ended up being the launching pad to the golden catalog.

After turning on Inspeckage and letting the app boot up for the first time we can see a few things. (1) https traffic, (2) files created zip/certs/js+img assets. I was hoping the SQLite tab would light up and we could query against .db file immediately but that would be too easy

Ripping things apart

Before getting into the .apk I figured it would be worthwhile to see what was stored on my device
adb shell && cd /data/data/com.package.name/
and… explore!

The main thing I was looking for here was something in the databases/ or files/ directories. Luckily we were able to spot a TARGET.db within files/databases but it was definitely encrypted (dreaded “file is encrypted or not a database” when querying)

Remember that if the app is not debuggable you won’t be able to adb pull /pathtoDBFile.db instead you’ll have to adb shell && su && mkdir /sdcard/data && cp /pathoDBFile /sdcard/data and then pull that file

Inspeckage has the handy download .apk so there’s a few things we can do here (starting with the most obvious)
– unzip it and take a look at what we’ve got

dan@dan-MacBookPro:~/riperino$ unzip og.apk
Archive:  og.apk
  inflating: META-INF/MANIFEST.MF
  inflating: META-INF/CATEXTKY.SF
  inflating: META-INF/CATEXTKY.RSA
  inflating: AndroidManifest.xml
  inflating: assets/_where-is-www.txt
  ...
 extracting: assets/icudt46l.zip
 extracting: assets/www/assets/
 .... a ton of assets (selected some potential highlights)
  inflating: assets/www/config/config.json
  inflating: assets/www/cordova.js
  inflating: assets/www/css/bootstrap/
  inflating: assets/www/js/
 extracting: res/drawable/icon.png
  inflating: res/xml/config.xml
 extracting: resources.arsc
  inflating: classes.dex
...
  inflating: lib/armeabi/libsqlcipher.so
  inflating: lib/armeabi-v7a/libsqlcipher.so
  inflating: lib/x86/libsqlcipher.so

From looking at the contents we can tell the basic structure but we are mostly interested in a few files
– libsqlcipher.so & assets/icudt46l.zip (interesting fallback zip for sqlcipher..possible fun attack vector)
– classes.dex (exactly what it says)

This confirms our hunch about SQLite and explains the missing contents from the SQLite tab while using Inspeckage. Now the hope is that classes.dex reveals something blatantly obvious..

Reading some code

There are quite a few tools for digging into the contents of that .dex file but I’ll go over my comfortable flow (unnecessary .dex -> .jar step with tools like Bytecode Viewer but the extra step does provide some extra possibilities if we really need to build a custom apk)

Using the dex2jar toolkit we can use the classic d2j-dex2jar to give us the handy .class files zipped to .jar (while not perfect this is almost always “good enough” for what we need)

After creating the .jar its time to pop open Java Decompiler and dig into the package in question.. And after a little while we run into this section of code (masterKey makes us happy and definitely worth hooking into?)

After reading the docs for getReadableDatabase it’s clear that’s indeed the SQLite password and if the developer also followed the documentation they would also have called createAndGetDBPath which would serve as the initialization.. Lo and behold the DBHelper.class implements that class and we can add a hook to ensure we catch the key when we reboot the app

Hooking and Winning

Without getting too tangential Xposed is great and the documentation is outstanding for anyone interesting in getting started. If the development tutorial is not enough the content online was more than enough to clear up any potential blockers.

public class Main implements IXposedHookLoadPackage {
    public void handleLoadPackage(final LoadPackageParam lpparam) throws Throwable {
        findAndHookMethod("com.****.core.db.DBHelper", lpparam.classLoader, "createAndGetDBPath", Context.class, String.class, new XC_MethodHook() {
            @Override
            protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                XposedBridge.log("Hooked em': DBHelper#createAndGetDBPath ");
                XposedBridge.log("----------------------------------------");
                XposedBridge.log(param.args[1].toString());
                XposedBridge.log("----------------------------------------");
            }
        });
    }
}

We load our hook module, reboot our device and when we rerun the app we see something beautiful in the logs

Hooked em': DBHelper#createAndGetDBPath
----------------------------------------
base64masterKey== (totally legit..)
----------------------------------------

Now I should be able to

Sqlcipher rippedDB.db
PRAGMA key=”base64masterKey==”
.tables

And get something other than file is encrypted or not a database. Unfortunately this didn’t work on my machine and I thought I was getting juked out and went to bed.

After thinking about questions like these (1, 2, 3) all night + the following day of family time it became clear versions must be the issue in my case. After figuring out the difference between Commercial and Community it became clear this was just a time save and the same version was being used for both and the commercial folks were just given the latest binaries without having to work for them. Since we have some compatriots who dont like working much either I ran brew install sqlcipher and of course things just worked..

Mac - 3.15.2
Ubuntu 16.04 - 3.8.6

As an additional aside there are some open source “sqlbrowser applications” that have sqlcipher as a feature but dont do a great job revealing the versioning. Just build community versions as they are released and things should be fine / bank on everyone being on commercial and brew updating at the same time 😀

Upon using the correct version we see a beautiful table list and can query to our heart’s content.

Retro

The entire sqlcipher seems incredibly trivial given the release strategy and knowing what we know about hooking. The fact that the key is going to be passed around no matter what makes things quite easy unless some additional precautions are taken but unfortunately it just moves the problem a step deeper. In the end the Android SQLDatabase methods are going to used and we can hook them no matter how many Proxys/Helpers are introduced to the codebase. After digging further into the Xposed modules someone wrote a generalized hook that looks for the specific sqlcipher native package to hook into.. This seems to reinforce my belief that it’s general uselessness but there must be a reason big companies are giving them money (other than the desire to avoid building it themselves)

Posted in reverse engineering | Leave a comment

Ixalan Draft #1

Black/Blue/White Deck

Didnt realize I messed up mana until I got home.. would have preferred a 664

  • 7 Swamp
  • 6 Island
  • 3 Plains
  • Ixalans Binding
  • Slash of Talons
  • Cancel
  • Spell Pierce
  • 3 One With the Wind
  • 2 Run Aground
  • 2 Depths of Desire
  • Duress
  • 2 Call to the Feast
  • Deadeye Plunderers
  • Anointed Deacon
  • Desperate Castaways
  • Wanted Scoundrels
  • Seekers Squire
  • Kinjallis Caller
  • Shining Aerosaur
  • Paladin of the Bloodstained
  • Prosperous Pirates
  • Sailor of Means
  • Shipwreck Looter

sideboard

  • Charging Monstrosaur
  • Dire Fleet Captain
  • Kinjallis Caller
  • Gilded Sentinel
  • Lookouts Dispersal
  • Queens Commission

This is the deck that I boxed up when I headed home.. Looking at it now I can see why I lost my last 2 matches

In my first game I ran Charging Monstrosaur (swapped after game for another One With the Wind since it won my the first game..not the best idea to run 3) and the second Kinjallis Caller which was played on turn 1 and proved to be an annoyance for my opponent (swapped for a second Call to the Feast.. not a bad card but wasnt necessary)

I ended up winning both games with a timely Ixalans Binding and One With the Wind which led me into a false sense of security for my next 2 matches (both of which I think I should have won)

Posted in Friday Night Magic, MTG | Leave a comment

Connecting to Shitty Wifi on Amtrak

I wrote this post a few months ago when I was stuck on a train and figured I’d publish it before it gets lost forever.

Today I bring you the pain in the ass process I went through to get a really shitty connection on my Amtrak ride

Connecting to the wifi network yields a proper connection (ip assigned & network-manager is happy)… but once you try to go to any page you are stopped..

dan@dan-MacBookPro:~/Documents$ ping google.com
PING google.com (172.217.6.78) 56(84) bytes of data.
^C
--- google.com ping statistics ---
19 packets transmitted, 0 received, 100% packet loss, time 18143ms

If we go to http://172.217.6.78:80 we will magically be redirected to www.amtrakconnect.com! The login page that failed to popup when the connection was established.

Even if we manually go to the URL your browser may get tripped up and timeout over and over again. While waiting for the browser why not curl that beezy?

A quick curl amtrakconnect.com will yield content so WTF is going on Mr. Browser? You must be getting stuck somewhere

Lets save the contents of that page to a file (!! > weblogin.html) and update any links to be absolute paths so all the php files load properly when we open it locally (we dont care about getting images/stylesheets to load).

To the source!! On first glance it should be pretty obvious that an ajax call is happening and we just need to click on an accept link to verify ourselves after its successful.

And voila we click on the link and are able to use the trash connection for the rest of the train ride.

Posted in travel, wifi | Leave a comment

Turbolinks: Leaving the Abyss

Just trying to do things like

<a href=”#” onclick=”alert(1)”>ZZZ</a>

Expected behavior here?.. Scroll to top of the page right? Not if turbolinks is doing its thang.

From my previous write-ups on Turbolinks (1 2) I was pretty understanding about the inherent behavioural differences for all things links.

If I wasn’t aware of Turbolinks I’d be incredibly confused by this incredibly simple bit of code. This time I was lucky enough to spot the Turbolinks loarder bar attempting to do unnecessary work and knew what the issue was

On top of initial confusion the fact that something like href=”#” doesn’t work according to spec is pretty frustrating and difficult to understand.

If we really want a link what do we do

<button> is your friend. Include Bootstrap and link style that SOB if you really want that link feel.. a bit annoying but easy enough to add to a project and remember class="btn btn-link"

The reason that works is because by default Turbolinks is only looking for <a href> links pointing to the current domain (of course we can turn this off w/ data-no-turbolinks='true'

All this additional knowledge for such little gain is not worth it. I don’t care to remember or reason about how Turbolinks will be handling history or trying to optimize potential page loads. Unless I’m building a single page app that has the same feel across all browsers and devices I’m not interested in the additional complexities.

No disrespect or hating on the idea for Rails 5 to include turbolinks by default; it’s understandable that to remain relevant in the app academy days of development folks are looking to build single page apps that will become the next hot thing.

I am officially on the rails new my_app --skip-turbolinks 🚂 now

Posted in Rails, turbolinks | Leave a comment

Horse’s Hoofs: Sagely Errors

Associated reading: Zhuangzi – Horse’s hoofs

TLDRBWPIKWG; The natural order is pretty chill but some “sagely dudes” threw a wrench in that real quick

## 1: Blindly Following “sagely” advice

Horses can with their hoofs tread on the hoarfrost and snow, and with their hair withstand the wind and cold; they feed on the grass and drink water; they prance with their legs and leap: this is the true nature of horses. Though there were made for them grand towers and large dormitories, they would prefer not to use them. But when Bo-le (arose and) said, ‘I know well how to manage horses,’ (men proceeded) to singe and mark them, to clip their hair, to pare their hoofs, to halter their heads, to bridle them and hobble them, and to confine them in stables and corrals. (When subjected to this treatment), two or three in every ten of them died.

Bo-Mi didn’t actually know shit about horses but he wanted to be the horse master so bad that he continually told plebs that he knew how to take care of these powerful beasts. People saw Mr. Mi riding around town and were like “fuck me I dont care if a few die, as long as I can do that” and naturally pushed the limits and soon 4|5/10 of the horses died but “dude I’m riding a horse” is logic that can’t be argued against..

And yet age after age men have praised Bo-le, saying, ‘He knew well how to manage horses,’ and also the (first) potter and carpenter, saying, ‘They knew well how to deal with clay and wood.’ This is just the error committed by the governors of the world.

What they are saying is we let this happen..

If only humanity had held onto the simplicity of Di for a little while longer

2: The section that’s better than Avatar

..Therefore in the age of perfect virtue men walked along with slow and grave step, and with their looks steadily directed forwards. At that time, on the hills there were no foot-paths, nor excavated passages; on the lakes there were no boats nor dams; all creatures lived in companies; and the places of their settlement were made close to one another. Birds and beasts multiplied to flocks and herds; the grass and trees grew luxuriant and long. In this condition the birds and beasts might be led about without feeling the constraint; the nest of the magpie might be climbed to, and peeped into. Yes, in the age of perfect virtue, men lived in common with birds and beasts, and were on terms of equality with all creatures, as forming one family – how could they know among themselves the distinctions of superior and inferior beings?

Damn Avatar was some deep shit huh? Equality of all creatures existing in nature seems like a pretty reasonable idea but always remember our favorite section from Matthew.. and remember this is a beloved early passage for the youngsters..

Matthew 6:26
Behold the fowls of the air: for they sow not, neither
do they reap, nor gather into barns; yet your heavenly
Father feedeth them. Are ye not much better than they?

Can’t say I Matthew’s sagely advice sits too well with me

Back to Zhuangzi..This idealistic view of the world of course has to be destroyed by a few sagely guys that think they know whats up..

In that state of pure simplicity, the nature of the people was what it ought to be. But when the sagely men appeared, limping and wheeling about in (the exercise of) benevolence, pressing along and standing on tiptoe in the doing of righteousness, then men universally began to be perplexed.

The cutting and hacking of the raw materials to form vessels was the crime of the skilful workman; the injury done to the characteristics of the Dao in order to the practice of benevolence and righteousness was the error of the sagely men.

When men began to live outside of their natural way they destroyed the Dao in order to pursue less noble goals. Zhuang Zhou recognizes that the damage has already been done and we can’t live in the natural ideal but a pursuit of wu wei is still worth the struggle.

3: Controlling lead to Unforseen Negatives

Horses, when living in the open country, eat the grass, and drink water; when pleased, they intertwine their necks and rub one another; when enraged, they turn back to back and kick one another – this is all that they know to do. But if we put the yoke on their necks, with the moonlike frontlet displayed on all their foreheads, then they know to look slily askance, to curve their necks, to rush viciously, trying to get the bit out of their mouths, and to filch the reins (from their driver); this knowledge of the horse and its ability thus to act the part of a thief is the crime of [the sagely men].

Zhuang Zhou wants us to really think about the natural horse. Where do many negative horse behaviors come from? Do they truly originate from humanity’s attempt manage and control the horses raw power? By controlling the horse has man created more problems? Does the advice of former sages lead to the problems of the world today?

But when the sagely men appeared, with their bendings and stoppings in ceremonies and music to adjust the persons of all, and hanging up their benevolence and righteousness to excite the endeavours of all to reach them, in order to comfort their minds, then the people began to stump and limp about in their love of knowledge, and strove with one another in their pursuit of gain, so that there was no stopping them: this was the error of those sagely men.

While this is a definite over simplification of the creeping in of evils into the world, the importance and danger of false truths about known unknowns should not be underemphasized. Throughout time we should expect more sagely men to appear with answers that greatly simplify and “improve” things; a little skepticism and pursuit of what is most natural is paramount.

Takeaway: The Daoist Natural Ideal

Somethings like the horse’s hoof should be left in its natural state rather than shoed to conform to the unnatural existance we have created and forced on it.

Posted in Daoism, Philosophy, Zhangzi | Leave a comment

Intercepting iOS Network Traffic on Mac

For the most part you are probably fine just using a solution like mitmproxy (shown here) and sniffing HTTP/S traffic but sometimes there’s a need to go deeper..

When testing an application you may notice something like an in-game chat server “not sending any requests” (w/ mitmproxy) when we are posting a new message to the server / getting messages from other players. Luckily for us we have some better tools to dig into all network activity on the device!

At some point Apple introduced a dev tool called rvictl (Remote Virtual Interface Tool) that allows us to create a seperate network interface for a connected device by providing its UDID. This allows us to use our favorite sniffing tool on the given device 😀

Find UDID

Connect your device
Open up iTunes, select the device, and copy the UDID (might have to click on serial number to get to it)

Create new interface

rvictl -s YOUR_UDID

The command should SUCCEED and you will see your new interface (eg. rvi0)

Sniff away

tcpdump or Wireshark away w/ the new interface and have fun with the extra requests on strange ports
:rocket:

Posted in recon, sniffing, Wireshark | Leave a comment