Using reverse engineering to stay alive

2018-06-25Michal

Let’s pretend you’re in a bad spot from the very beginning of this article: you’re ill. Your stomach hurts, it doesn’t stop for a couple of weeks – internet says you’ve probably got cancer and you need to get yourself checked. And you plan to. But what if all of the local doctors have their calendars full, your health problems don’t fall into the “medical emergency” category and your private medical insurance does indeed offer you an appointment, but no earlier than in 3 months?

A word of wisdom

Cancer is a bitch. I’ve had my family and loved ones fighting and while they’ve all been successful, I know the key for beating that piece of crap is early detection. So if you have any symptoms or are old enough for routine screenings (I recommend starting as early as in your thirties) then please don’t hesitate and get yourself checked, no matter how intimidating it seems to be. It’s better to suffer a day, but live for decades.

Assessing the options

But going back to the journey: you need a doctor pretty quickly. What exactly are your choices? Let’s see how it looks in Poland, where I live.

  • There’s a free public health service.
    • BUT: While it’s free, unless it’s qualified as a medical emergency you won’t get an appointment with a specialist anytime soon. If you are lucky you will have to wait about 6 months – and that’s not too long, considering that people need to wait 5-10 years to see a cardiologist if they want to see one for free.
  • Use your private health insurance and book an appointment with one of your provider’s doctors.
    • BUT: While you can easily book online, if you don’t luck out and someone cancels, the first available appointment will be in 2-3 months, and that’s still a lot of waiting.
  • Try to find a doctor online and book a private appointment.
    • BUT: Appointments like these are expensive and unfortunately are none available for about a month from now. And you’re in constant pain.

No option looks too good, eh? Well… you remember that part about lucking out? What if you would be able to aid your luck? Let’s take a closer look at some appointment booking software.

How does this thing work?

My private medical insurance provider – let’s call them Mediocre Medical, MM in short – is one of the top 3 insurance providers in my country. Let’s assume you  want to go with that one. They have about 20 medical centers just in my city and offer a fairly inexpensive plan, where you pay a yearly fee, but then you get a 90% discount for some of their services – that includes blood tests, specialist appointments, etc. They have a website and a mobile app, both offering an ability to book appointments, check your blood work results, etc. They also both follow the same procedure when it comes to booking those appointments:

  1. You log into your MM personal account
  2. You select the type of appointment you need
  3. (Optional) You select MM’s venue for that appointment
  4. (Optional) You select a specific doctor at that venue
  5. You select a date range or choose “first available”
  6. You select a specific date and time from a displayed list of available appointments

 

About 24 hours before your visit you get an SMS with a reminder. You can obviously cancel at any time without any problems or additional fees. Some people do that, so if you’re lucky and somebody just decided to forfeit, you can jump right in into their spot. But that would require waking up at 8 AM and doing a search every 5 minutes – and this is certainly not something you would like to do. So let’s try to automate it!

The technical stuff

We can try to do that with a web browser script or a C# program with an embedded browser that basically does what a human being does, but with Javascript calls instead of actual mouse clicking. That may work fairly OK, but having to deal with page load timings (because some of the ASP.NET code loaded after a few seconds), cookies, CSRF tokens, CSS classes and IDs being duplicate and fairly imprecise… Not the best choice.

MM also offers a mobile app – which offers the same as their web-based counterpart, but communicates with their servers differently. We can use Fiddler (which is a cool piece of software that serves as a proxy, allowing you to intercept and manipulate web traffic) to check out what behind-the-scenes stuff does MM’s mobile app do. Setting up Fiddler as a proxy in your mobile WiFi settings and installing an SSL certificate from Fiddler allows you to use your computer to intercept almost all the HTTP traffic between your mobile device and the internet – even if it’s encrypted over HTTPS.

This pretty much means that if you reverse-engineer the mobile app API calls, you can create a script in your favorite programming language that acts exactly the same as the mobile app. This could serve as a great basis for automation.

Analyzing the API

First of all it’s worth quickly explaining what an API is and how it works. While the super cool glossary built in this blog probably did explain the acronym, there’s a super simple principle behind that. I’ll chart this one for you:

In summary, all that a client does is sends HTTP requests using mostly GET and POST methods, calling a certain URL and a couple of parameters. Those requests get processed and then a response is sent back to the client. Not too hard, ain’t it? Now, both requests and responses contain two parts: headers and body. In headers you usually store metadata concerning what kind of a message this is (encoding, sender user-agent/browser data, content type, some unique identifiers), while the body contain actual contents of the message.

Let’s check what does the MM API actually do by making a fairly random appointment in the mobile app and then canceling it on a smartphone. By catching all the HTTP traffic with Fiddler we can analyze what did just happen in the background (parts of the URLs are blurred because I’m not sure how local law likes this):

So we’ve got 13 API calls from start to finish. They have fairly standard headers (only a custom user-agent and an additional header called “x-api-client-identifier”), but after sending your login and password you get a security token, which you need to use to identify yourself going forward. All the responses are in JSON. Here’s a list of the most important API calls along with their description:

  1. URL: /token
    Type: POST
    Request: username and password
    Response: security token
    What does it do: You send your username and password + some client data, and if it’s correct you get a security token that let’s you use the rest of the API.
  2. URL: /api/visits/available-terms/reservation-filter
    Type:
    GET
    Request:
    date range, city ID, clinic ID, service ID, doctor ID
    Response: list of cities, (if city ID provided) list of clinics in the city, (if clinic ID is provided) list of services in the clinic, (if service ID provided) list of doctors who offer in the clinic who offer this service
    What does it do: This is a good one to gather all the necessary information and IDs to specify what exact appointment do you want, when and where. You can call it a few times gradually providing more information to get more specific info too.
  3. URL: /api/visits/temporary-reservation
    Type: POST
    Request: Clinic ID, Service ID, Doctor ID, Appointment Date/time and a whole lot of personal MM account information
    Response: Temporary Reservation ID
    What does it do: You use this one to make a temporary reservation. I’m not sure what’s the purpose of that, but I assume it’s to “lock” the time slot of the doctor, so if there are any additional confirmations required in the user interface nobody steals your appointment before you confirm everything.
  4. URL: /api/visits/reserved
    Type: GET
    Request: Date/time range
    Response: List of reserved visits
    What does it do: Allows you to get a you a full list of your reserved appointments along with their IDs – so you can use them to cancel.

There’s a few more, but I’ll skip them, because nobody would want to read through a list of boring API call descriptions, when we can just get straight into the juicy stuff – and that’s obviously faking being a mobile app and using the API calls to do fancy automated stuff.

A snake that pretends

When it comes to coding automated API requests I love to use Python – aside of having a great Requests library, which as the name suggests implements an easy way to handle web requests, you can also leave it running unattended on a remote Linux server and just wait for the results. What do we need to pretend we’re a mobile app when doing web request calls? Imagine for a moment we’re going to visit someone to pretend we’re someone else to get an item. We need:

  1. API endpoint URL – to know where to go knocking
  2. API method names – to know which door to knock
  3. Request headers – to know who to dress as
  4. Request parameters – to know what to say to get what we want
  5. API response – to finally take the item we want

Fortunately Fiddler gives us all of that – here’s an example request and response screenshot:

How do we implement this in Python? Here’s an example method to get an authorization token from the API:

def getToken(username, password): 
   baseUrl = 'https://mobileapi.mm.pl'
   methodPath = '/token'
 
   reqHeaders = dict()
   reqHeaders['User-Agent'] = 'MMMobile/2.0 (build:1120; iOS 11.1.2) Alamofire/4.5.1'
   reqHeaders['Accept-Encoding'] = 'gzip;q=1.0, compress;q=0.5'
   reqHeaders['Accept-Language'] = 'pl-PL;q=1.0, en-PL;q=0.9'
   reqHeaders['x-api-client-identifier'] = 'iPhone'

   reqParams= {
      'client_id':'iPhone',
      'grant_type':'password',
      'password': password,
      'username': username
      }

   req = requests.post(baseUrl + methodPath, data = reqParams, headers = reqHeaders, verify = True)

   if 'Errors' not in req.json():
      token = req.json()['access_token']
      return token
   else:
      return None

Then you can get the authorization token using a following call:

myToken = getToken('myUsername', 'myPassword')

After that you can pretty much copy that example and re-implement it for different API calls – of course the data returned and parameters required will be different, but you just need to use Fiddler to analyze each call and then implement required parameters in Python and implement returning the right response.

After a couple of hours of coding I’ve ended up with a class called MmApi, with the following methods:

  • getToken() – returns the authorization token
  • getReservedVisits(fromDate, toDate) – returns a list of my currently and previously reserved appointments
  • getCities() – returns a list of cities that MM provides its services in
  • getClinics(cityId) – returns a list of MM clinics for a particular city ID
  • getServices(cityId, clinicId=None) – returns a list of services available in selected city (or optionally in a selected clinic)
  • getPayers(serviceId, cityId) – returns a list of your payment plans that you can use for the selected servic
  • getDoctors(serviceId, cityId, clinicId=None) – returns a list of doctors that provide the selected service in your selected city (or optionally – selected clinic)
  • getAppointments(serviceId, payerId, cityId, clinicId, timeOfDay=0, fromDate, toDate) returns a list of possible appointments for a selected service, payment plan, city,  time of day and date ranges
  • bookAppointment(payerData, serviceId, clinicId, doctorId, roomId, startDateTime) – allows you to book a specific appointment based on provided parameters
  • cancelAppointment(appointmentId) – allows you to cancel a previous appointment (handy if you find a free spot earlier than what you already have booked)

Using those I was able to code a script that runs on a server and allows for three things:

  1. E-mail you if there’s a free appointment for you in the next x days
  2. Book an appointment for you if the above is true
  3. Cancel an appointment and book one earlier if a spot is free

Searching for an appointment happens every 10 minutes until it finds one and does one of the actions above.

To leave it unattended, I just run it on my server using tmux – a terminal multiplexer, which outside of providing you with multiple simultaneous terminal windows also allows the script to run after you close your terminal – so it’s not aborted and searches stuff for you in the background.

The result

Back to you then – you are alive and well now. Fortunately it was nothing more than an inflammation that was curable with a couple weeks of medication. Before you got diagnosed you had to visit a  gastroenterologist five times and undergo three fairly invasive medical procedures, all of which required booking and had about the same waiting time of three weeks.

Let’s do some math and calculate the total time to diagnosis:

Variant A – no cheating:

5 specialist appointments * 2 months of waiting time = 10 months
3 medical procedures * 3 weeks of waiting time = 9 weeks (2 months + 1 week)

Total time: about 375 days (12 months + 1 week)

Variant B – with the blessing of automation:

5 specialist appointments * a maximum of 5 days of waiting time = 25 days
3 medical procedures * a maximum of 5 days of waiting time = 15 days

Total time: 40 days (a month + a week and a half)

A summary – can reverse engineering really save your life?

I’m not a medical professional, but I’ve heard about cases where if diagnosed earlier people would recover fully – or at least be still alive. In some edge cases the time to diagnose being shorter by 11 months could literally save your life. So to answer the question asked in the header – yes, reverse engineering can really save your life – at least in theory.

Leave a comment

Your email address will not be published. Required fields are marked *

Prev Post Next Post