欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

[原创]某商城的电子书加密分析

[原创]某商城的电子书加密分析

当初某商城的电子书不提供下载,只能在线阅读。而阅读器的界面实在反人类,因此有了分析的想法。
这方面已经有一篇前人的经验总结。虽然因为时间久远已经失效,但其中的原理是相通的。
首先用chrome查看网络通信,发现每次翻页都会产生一个请求,显然这是每一页的内容。根据前文所述,这是一个带文件头的加密swf,但这次的文件头与文中说的不一样,应该是改了算法。
继续按文中的思路,反编译reader.swf,不出所料在application.view.DupLoader发现了感兴趣的东西。画成示意图如下。

其中唯一的难点是最开始的密文怎么得到。脚本中是一个名为hexKey的变量,逐步追踪,线索指向application.view.reader,最后才弄明白这是名为AMF的flash通信协议,可调用服务器端的函数。于是用pyamf模拟,发现返回值是固定的,后面就偷懒直接用了。
整体而言,这套加密方法还是比较清晰的。主要原因是正文的内容实在太多,没法实时加密,只能事先加密之后存储,这样就只能在文件头上想办法,于是就有了上面迭床架屋式的加密。受限于flash的处理能力又没办法做得很复杂,于是就变成现在这样了。
分析完毕用python写个脚本测试。发现前20页(商城中可以免费试读的部分)正常,后面的取不到,怀疑是没加cookie认证失败造成的。由于python的cookiejar与chrome的格式不太兼容,又重新换回wget,就是最终的程序了。
取到swf之后用swf2video批量转换成png,再用freepic2pdf合并成pdf,最后用briss切边,就可以放进eink里看了。不足之处是图片格式的pdf体积较大,可以再用其他软件优化。
最后放出python脚本的代码,供研究讨论


#!/usr/bin/python

#USE AT YOUR OWN RISK

from pyamf.remoting.client import RemotingService

import logging

from Crypto.Cipher import AES

import base64

from Crypto.Cipher import ARC4

import sys

import subprocess

import os

BS=16

pad = lambda s: s + (BS - len(s) % BS) * chr(BS - len(s) % BS)

unpad = lambda s : s[0:-ord(s[-1])]

if(len(sys.argv) < 5):

	print "Usage: dangdown.py bookID startPages endPages bookCookieFile"

	sys.exit()

bookID = sys.argv[1]

startPages = int(sys.argv[2])

endPages = int(sys.argv[3])

bookCookieFile = sys.argv[4]

def gethexkey():

	logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(levelname)-5.5s [%(name)s] %(message)s')

	agent="Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.32 Safari/537.36"

	client = RemotingService('http://e.dangdang.com/datasvr/messagebroker/amf', logger=logging, user_agent=agent)

	client.addHTTPHeader("Origin", "http://e.dangdang.com")

	client.addHTTPHeader("Accept-Encoding","gzip,deflate,sdch")

	client.addHTTPHeader("Host","e.dangdang.com")

	client.addHTTPHeader("Accept-Language","zh-CN,zh;q=0.8")

	client.addHTTPHeader("Content-Type","application/x-amf;charset=UTF-8")

	client.addHTTPHeader("Accept","*/*")

	client.addHTTPHeader("Referer","http://e.dangdang.com/html/reader.swf?v=121130/[[DYNAMIC]]/12")

	client.addHTTPHeader("Cookie","JSESSIONID=4B6CEC0EF9531C926A2BFFFC2716D714")

	service = client.getService('ebookManager')

	return service.getHexKey()

def decryptSwf(pageno):

	filehandle = open('%d.swf'%(pageno), "rb")

	status=filehandle.read(1)

	status=int(ord(status))

	if(status != 3):

		print "error in %d, status %d"%(pageno, status)

		sys.exit()

	hexKeyHex="4723e225d1e3924f88ec9429600e4e9ad4b93608b8c78fcd9928dfb9ec7279dfd503f590a12e969c4a868daf36b838d8"

	readerKeyHex="843c3748ad8722b387100a629f4a0f61"

	readerKey=readerKeyHex.decode("hex")

	hexKey=hexKeyHex.decode("hex")

	aescipher = AES.new(readerKey,AES.MODE_ECB)

	serverKeyHex = aescipher.decrypt(hexKey)

	serverKeyHex = unpad(serverKeyHex)

	serverKey=serverKeyHex.decode("hex")

	swfHeaderHex=filehandle.read(64)

	swfHeader=swfHeaderHex.decode("hex")

	aescipher = AES.new(serverKey, AES.MODE_ECB)

	swfKeyHex=aescipher.decrypt(swfHeader)

	finalKey=base64.b64decode(swfKeyHex)

	rccipher = ARC4.new(finalKey)

	buf = filehandle.read()

	buf = rccipher.decrypt(buf)

	filehandle.close()

	os.remove('%d.swf'%(pageno))

	fswf = open("page%04d.swf"%(i) , "wb")

	fswf.write(buf)

	fswf.close()

	return

for i in range(startPages,endPages+1):

	strURL="wget -q -O %d.swf --load-cookies %s --user-agent='Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.32 Safari/537.36' --header='Host: e.dangdang.com' --header='Referer: http://e.dangdang.com/html/reader.swf?v=121130/[[DYNAMIC]]/12' http://e.dangdang.com/datasvr/permissionAuth.do?bookUid=%s\&pageNo=%d"%(i, bookCookieFile, bookID, i)

	subprocess.check_call(strURL, shell=True)

	decryptSwf(i)

	print i

上传的附件 dangdang.png

注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途。
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功