https://github.com/x43x61x69/Easy-Card
But he only released the .pyc file.
I tool a glance on the binary file and smiled, he didn't apply any code obfuscation on that, that is, it would be pretty easy for those who want to read the source code.
With the help of this tool: https://github.com/wibiti/uncompyle2
uncompyle2 easycard.pyc > easycard.py
You can decompile that yourself.
Basically the API takes 4 parameters: verify, cardID, begin, end.
verify = md5((seed * const) + salt)
where
seed = date.month + date.day + date.hour
salt = 'L0CalKing'
const = 8544
cardID = base64( des3( data, key, iv, mode=DEC3.MODE_CBC) )
where
data = 'your card ID', like '1234567889'
key = 'EasyCardToKingay23456789
iv = '01234567'
begin / end = time period
I'm really curious about how did he get these constants , but I don't want to dig up the original app. :)
Lesson: don't release .pyc file without code obfuscation if you really don't want any people try to dig up your code.
Code listing (partially omitted):
#!/usr/bin/env python2 # -*- encoding: utf8 -*- # 2015.05.04 17:41:47 CST import sys import datetime import hashlib import urllib import urllib2 import json from Crypto.Cipher import DES3 import pytz version = '0.3' copyright = 'Copyright (C) 2015 Zhi-Wei Cai.' key = 'EasyCardToKingay23456789' iv = '01234567' salt = 'L0CalKing' const = 8544 def getID(data, isEncrypt, key, iv, encode): size = len(data) # '\x06' is the padding of DES3 if size % 16 != 0: data += '\x06' * (16 - size % 16) des3 = DES3.new(key, DES3.MODE_CBC, iv) if isEncrypt: result = des3.encrypt(data).encode(encode).rstrip() else: result = des3.decrypt(data.decode(encode)) return result def getVerify(const, seed, salt): hash = hashlib.md5() hash.update(str(seed * const) + salt) return hash.hexdigest().upper() def proc(data): e = getID(data, 1, key, iv, 'base64') cardID = urllib.quote_plus(e) date = datetime.datetime.now(pytz.timezone('Asia/Taipei')) seed = date.month + date.day + date.hour begin = '{:%Y-%m-%d}'.format(date - datetime.timedelta(days=30)) end = '{:%Y-%m-%d}'.format(date) verify = getVerify(const, seed, salt) url = '<Easy Card API URL>'.format(verify, cardID, begin, end) req = urllib2.Request(url) response = urllib2.urlopen(req) content = response.read() dict = json.loads(content) # the rest part of the code is omitted if __name__ == '__main__': print '\n悠遊卡餘額明細查詢 v{}'.format(version) print '{}\n'.format(copyright) if len(sys.argv) > 1: try: print '\n{:=^90}\n'.format('[ 查詢開始 ]') proc(str(sys.argv[1])) except ValueError as err: pass else: while 1: try: data = raw_input('請輸入卡片號碼:').replace(' ', '') if len(data): print '\n{:=^90}\n'.format('[ 查詢開始 ]') proc(data) else: break except ValueError as err: pass #+++ okay decompyling easycard.pyc # decompiled 1 files: 1 okay, 0 failed, 0 verify failed # 2015.05.04 17:41:47 CST
No comments:
Post a Comment