mirror of
https://github.com/noDRM/DeDRM_tools.git
synced 2026-03-20 13:08:55 +00:00
Compare commits
3 Commits
f86cff285b
...
autoreleas
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9ae77c438f | ||
|
|
abc5de018e | ||
|
|
133e67fa03 |
44
.github/workflows/main.yml
vendored
44
.github/workflows/main.yml
vendored
@@ -9,8 +9,10 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Package
|
||||
run: python3 make_release.py
|
||||
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
@@ -18,3 +20,45 @@ jobs:
|
||||
path: |
|
||||
DeDRM_tools_*.zip
|
||||
DeDRM_tools.zip
|
||||
|
||||
- name: Delete old release
|
||||
uses: cb80/delrel@latest
|
||||
with:
|
||||
tag: autorelease
|
||||
token: ${{ github.token }}
|
||||
|
||||
- name: Delete old tag
|
||||
uses: dev-drprasad/delete-tag-and-release@v1.0
|
||||
with:
|
||||
tag_name: autorelease
|
||||
github_token: ${{ github.token }}
|
||||
delete_release: true
|
||||
|
||||
- name: Prepare release
|
||||
run: cp DeDRM_tools.zip DeDRM_alpha_${{ github.sha }}.zip
|
||||
|
||||
- name: Auto-release
|
||||
id: autorelease
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
tag_name: autorelease
|
||||
token: ${{ github.token }}
|
||||
name: Automatic alpha release with latest changes
|
||||
body: |
|
||||
This release is automatically generated by Github for each commit.
|
||||
|
||||
This means, every time a change is made to this repo, this release will be updated to contain an untested copy of the plugin at that stage. This will contain the most up-to-date code, but it's not tested at all and may be broken.
|
||||
|
||||
Last update based on Git commit ${{ github.sha }}.
|
||||
prerelease: true
|
||||
draft: true
|
||||
files: DeDRM_alpha_${{ github.sha }}.zip
|
||||
|
||||
- name: Make release public
|
||||
uses: irongut/EditRelease@v1.2.0
|
||||
with:
|
||||
token: ${{ github.token }}
|
||||
id: ${{ steps.autorelease.outputs.id }}
|
||||
draft: false
|
||||
prerelease: true
|
||||
|
||||
|
||||
@@ -57,6 +57,7 @@ except ImportError:
|
||||
# Windows-friendly choice: pylzma wheels
|
||||
import pylzma as lzma
|
||||
|
||||
from kfxtables import *
|
||||
|
||||
TID_NULL = 0
|
||||
TID_BOOLEAN = 1
|
||||
@@ -769,6 +770,7 @@ def pkcs7unpad(msg, blocklen):
|
||||
|
||||
|
||||
# every VoucherEnvelope version has a corresponding "word" and magic number, used in obfuscating the shared secret
|
||||
# 4-digit versions use their own obfuscation/scramble. It does not seem to depend on the "word" and number
|
||||
OBFUSCATION_TABLE = {
|
||||
"V1": (0x00, None),
|
||||
"V2": (0x05, b'Antidisestablishmentarianism'),
|
||||
@@ -779,26 +781,26 @@ OBFUSCATION_TABLE = {
|
||||
"V7": (0x05, b'\x10\x1bJ\x18\nh!\x10"\x03>Z\'\r\x01]W\x06\x1c\x1e?\x0f\x13'),
|
||||
"V8": (0x09, b"K\x0c6\x1d\x1a\x17pO}Rk\x1d'w1^\x1f$\x1c{C\x02Q\x06\x1d`"),
|
||||
"V9": (0x05, b'X.\x0eW\x1c*K\x12\x12\t\n\n\x17Wx\x01\x02Yf\x0f\x18\x1bVXPi\x01'),
|
||||
"V10": (0x07, b'z3\n\x039\x12\x13`\x06=v,\x02MTK\x1e%}L\x1c\x1f\x15\x0c\x11\x02\x0c\n8\x17p'),
|
||||
"V10": (0x07, b'z3\n\x039\x12\x13`\x06=v;\x02MTK\x1e%}L\x1c\x1f\x15\x0c\x11\x02\x0c\n8\x17p'),
|
||||
"V11": (0x05, b'L=\nhVm\x07go\n6\x14\x06\x16L\r\x02\x0b\x0c\x1b\x04#p\t'),
|
||||
"V12": (0x06, b',n\x1d\rl\x13\x1c\x13\x16p\x14\x07U\x0c\x1f\x19w\x16\x16\x1d5T'),
|
||||
"V12": (0x06, b';n\x1d\rl\x13\x1c\x13\x16p\x14\x07U\x0c\x1f\x19w\x16\x16\x1d5T'),
|
||||
"V13": (0x07, b'I\x05\t\x08\x03r)\x01$N\x0fr3n\x0b062D\x0f\x13'),
|
||||
"V14": (0x05, b"\x03\x02\x1c9\x19\x15\x15q\x1057\x08\x16\x0cF\x1b.Fw\x01\x12\x03\x13\x02\x17S'hk6"),
|
||||
"V15": (0x0A, b'&,4B\x1dcI\x0bU\x03I\x07\x04\x1c\t\x05c\x07%ws\x0cj\t\x1a\x08\x0f'),
|
||||
"V16": (0x0A, b'\x06\x18`h,b><\x06PqR\x02Zc\x034\n\x16\x1e\x18\x06#e'),
|
||||
"V16": (0x0A, b'\x06\x18`h;b><\x06PqR\x02Zc\x034\n\x16\x1e\x18\x06#e'),
|
||||
"V17": (0x07, b'y\r\x12\x08fw.[\x02\t\n\x13\x11\x0c\x11b\x1e8L\x10(\x13<Jx6c\x0f'),
|
||||
"V18": (0x07, b'I\x0b\x0e,\x19\x1aIa\x10s\x19g\\\x1b\x11!\x18yf\x0f\t\x1d7[bSp\x03'),
|
||||
"V18": (0x07, b'I\x0b\x0e;\x19\x1aIa\x10s\x19g\\\x1b\x11!\x18yf\x0f\t\x1d7[bSp\x03'),
|
||||
"V19": (0x05, b'\n6>)N\x02\x188\x016s\x13\x14\x1b\x16jeN\n\x146\x04\x18\x1c\x0c\x19\x1f,\x02]'),
|
||||
"V20": (0x08, b'_\r\x01\x12]\\\x14*\x17i\x14\r\t!\x1e,~hZ\x12jK\x17\x1e*1'),
|
||||
"V20": (0x08, b'_\r\x01\x12]\\\x14*\x17i\x14\r\t!\x1e;~hZ\x12jK\x17\x1e*1'),
|
||||
"V21": (0x07, b'e\x1d\x19|\ty\x1di|N\x13\x0e\x04\x1bj<h\x13\x15k\x12\x08=\x1f\x16~\x13l'),
|
||||
"V22": (0x08, b'?\x17yi$k7Pc\tEo\x0c\x07\x07\t\x1f,*i\x12\x0cI0\x10I\x1a?2\x04'),
|
||||
"V23": (0x08, b'\x16+db\x13\x04\x18\rc%\x14\x17\x0f\x13F\x0c[\t9\x1ay\x01\x1eH'),
|
||||
"V24": (0x06, b'|6\\\x1a\r\x10\nP\x07\x0fu\x1f\t,\rr`uv\\~55\x11]N'),
|
||||
"V25": (0x09, b'\x07\x14w\x1e,^y\x01:\x08\x07\x1fr\tU#j\x16\x12\x1eB\x04\x16=\x06fZ\x07\x02\x06'),
|
||||
"V24": (0x06, b'|6\\\x1a\r\x10\nP\x07\x0fu\x1f\t;\rr`uv\\~55\x11]N'),
|
||||
"V25": (0x09, b'\x07\x14w\x1e;^y\x01:\x08\x07\x1fr\tU#j\x16\x12\x1eB\x04\x16=\x06fZ\x07\x02\x06'),
|
||||
"V26": (0x06, b'\x03IL\x1e"K\x1f\x0f\x1fp0\x01`X\x02z0`\x03\x0eN\x07'),
|
||||
"V27": (0x07, b'Xk\x10y\x02\x18\x10\x17\x1d,\x0e\x05e\x10\x15"e\x0fh(\x06s\x1c\x08I\x0c\x1b\x0e'),
|
||||
"V28": (0x0A, b'6P\x1bs\x0f\x06V.\x1cM\x14\x02\n\x1b\x07{P0:\x18zaU\x05'),
|
||||
"V9708": (0x05, b'\x1diIm\x08a\x17\x1e!am\x1d\x1aQ.\x16!\x06*\}x04\x11\t\x06\x04?'),
|
||||
"V9708": (0x05, b'\x1diIm\x08a\x17\x1e!am\x1d\x1aQ.\x16!\x06*\x04\x11\t\x06\x04?'),
|
||||
"V1031": (0x08, b'Antidisestablishmentarianism'),
|
||||
"V2069": (0x07, b'Floccinaucinihilipilification'),
|
||||
"V9041": (0x06, b'>\x14\x0c\x12\x10-\x13&\x18U\x1d\x05Rlt\x03!\x19\x1b\x13\x04]Y\x19,\t\x1b'),
|
||||
@@ -807,10 +809,367 @@ OBFUSCATION_TABLE = {
|
||||
"V9479": (0x09, b'\x10\x1bJ\x18\nh!\x10"\x03>Z\'\r\x01]W\x06\x1c\x1e?\x0f\x13'),
|
||||
"V9888": (0x05, b"K\x0c6\x1d\x1a\x17pO}Rk\x1d'w1^\x1f$\x1c{C\x02Q\x06\x1d`"),
|
||||
"V4648": (0x07, b'X.\x0eW\x1c*K\x12\x12\t\n\n\x17Wx\x01\x02Yf\x0f\x18\x1bVXPi\x01'),
|
||||
"V5683": (0x05, b'z3\n\x039\x12\x13`\x06=v,\x02MTK\x1e%}L\x1c\x1f\x15\x0c\x11\x02\x0c\n8\x17p'),
|
||||
"V5683": (0x05, b'z3\n\x039\x12\x13`\x06=v;\x02MTK\x1e%}L\x1c\x1f\x15\x0c\x11\x02\x0c\n8\x17p'),
|
||||
}
|
||||
|
||||
|
||||
#common str: "PIDv3AESAES/CBC/PKCS5PaddingHmacSHA256"
|
||||
class workspace(object):
|
||||
def __init__(self,initial_list):
|
||||
self.work=initial_list
|
||||
def shuffle(self,shuflist):
|
||||
ll=len(shuflist)
|
||||
rt=[]
|
||||
for i in range(ll):
|
||||
rt.append(self.work[shuflist[i]])
|
||||
self.work=rt
|
||||
def sbox(self,table,matrix,skplist=[]): #table is list of 4-byte integers
|
||||
offset=0
|
||||
nwork=list(self.work)
|
||||
wo=0
|
||||
toff=0
|
||||
while offset<0x6000:
|
||||
uv5=table[toff+nwork[wo+0]]
|
||||
uv1=table[toff+nwork[wo+1]+0x100]
|
||||
uv2=table[toff+nwork[wo+2]+0x200]
|
||||
uv3=table[toff+nwork[wo+3]+0x300]
|
||||
moff=0
|
||||
if 0 in skplist:
|
||||
moff+=0x400
|
||||
else:
|
||||
nib1=matrix[moff+offset+(uv1>>0x1c)|( (uv5>>0x18)&0xf0)]
|
||||
moff+=0x100
|
||||
nib2=matrix[moff+offset+(uv3>>0x1c)|( (uv2>>0x18)&0xf0)]
|
||||
moff+=0x100
|
||||
nib3=matrix[moff+offset+((uv1>>0x18)&0xf) |( (uv5>>0x14)&0xf0)]
|
||||
moff+=0x100
|
||||
nib4=matrix[moff+offset+((uv3>>0x18)&0xf) |( (uv2>>0x14)&0xf0)]
|
||||
moff+=0x100
|
||||
rnib1=matrix[moff+offset+nib1*0x10+nib2]
|
||||
moff+=0x100
|
||||
rnib2=matrix[moff+offset+nib3*0x10+nib4]
|
||||
moff+=0x100
|
||||
nwork[wo+0]=rnib1*0x10+rnib2
|
||||
if 1 in skplist:
|
||||
moff+=0x400
|
||||
else:
|
||||
nib1=matrix[moff+offset+((uv1>>0x14)&0xf)|( (uv5>>0x10)&0xf0)]
|
||||
moff+=0x100
|
||||
nib2=matrix[moff+offset+((uv3>>0x14)&0xf)|( (uv2>>0x10)&0xf0)]
|
||||
moff+=0x100
|
||||
nib3=matrix[moff+offset+((uv1>>0x10)&0xf) |( (uv5>>0xc)&0xf0)]
|
||||
moff+=0x100
|
||||
nib4=matrix[moff+offset+((uv3>>0x10)&0xf) |( (uv2>>0xc)&0xf0)]
|
||||
moff+=0x100
|
||||
|
||||
rnib1=matrix[moff+offset+nib1*0x10+nib2]
|
||||
moff+=0x100
|
||||
rnib2=matrix[moff+offset+nib3*0x10+nib4]
|
||||
moff+=0x100
|
||||
nwork[wo+1]=rnib1*0x10+rnib2
|
||||
if 2 in skplist:
|
||||
moff+=0x400
|
||||
else:
|
||||
nib1=matrix[moff+offset+((uv1>>0xc)&0xf)|( (uv5>>0x8)&0xf0)]
|
||||
moff+=0x100
|
||||
nib2=matrix[moff+offset+((uv3>>0xc)&0xf)|( (uv2>>0x8)&0xf0)]
|
||||
moff+=0x100
|
||||
nib3=matrix[moff+offset+((uv1>>0x8)&0xf) |( (uv5>>0x4)&0xf0)]
|
||||
moff+=0x100
|
||||
nib4=matrix[moff+offset+((uv3>>0x8)&0xf) |( (uv2>>0x4)&0xf0)]
|
||||
moff+=0x100
|
||||
rnib1=matrix[moff+offset+nib1*0x10+nib2]
|
||||
moff+=0x100
|
||||
rnib2=matrix[moff+offset+nib3*0x10+nib4]
|
||||
moff+=0x100
|
||||
nwork[wo+2]=rnib1*0x10+rnib2
|
||||
if 3 in skplist:
|
||||
moff+=0x400
|
||||
else:
|
||||
nib1=matrix[moff+offset+((uv1>>0x4)&0xf)|( (uv5)&0xf0)]
|
||||
moff+=0x100
|
||||
nib2=matrix[moff+offset+((uv3>>0x4)&0xf)|( (uv2)&0xf0)]
|
||||
moff+=0x100
|
||||
nib3=matrix[moff+offset+((uv1)&0xf)|( (uv5<<4)&0xf0) ]
|
||||
moff+=0x100
|
||||
nib4=matrix[moff+offset+((uv3)&0xf)|( (uv2<<4)&0xf0) ]
|
||||
moff+=0x100
|
||||
##############
|
||||
rnib1=matrix[moff+offset+nib1*0x10+nib2]
|
||||
moff+=0x100
|
||||
rnib2=matrix[moff+offset+nib3*0x10+nib4]
|
||||
moff+=0x100
|
||||
nwork[wo+3]=rnib1*0x10+rnib2
|
||||
offset = offset + 0x1800
|
||||
wo+=4
|
||||
toff+=0x400
|
||||
self.work=nwork
|
||||
def lookup(self,ltable):
|
||||
for a in range(len(self.work)):
|
||||
self.work[a]=ltable[a]
|
||||
def exlookup(self,ltable):
|
||||
lookoffs=0
|
||||
for a in range(len(self.work)):
|
||||
self.work[a]=ltable[self.work[a]+lookoffs]
|
||||
lookoffs+=0x100
|
||||
def mask(self, chunk):
|
||||
out=[]
|
||||
for a in range(len(chunk)):
|
||||
self.work[a]=self.work[a]^chunk[a]
|
||||
out.append(self.work[a])
|
||||
return out
|
||||
|
||||
def process_V9708(st):
|
||||
#e9c457a7dae6aa24365e7ef219b934b17ed58ee7d5329343fc3aea7860ed51f9a73de14351c9
|
||||
ws=workspace([0x11]*16)
|
||||
repl=[0,5,10,15,4,9,14,3,8,13,2,7,12,1,6,11]
|
||||
remln=len(st)
|
||||
sto=0
|
||||
out=[]
|
||||
while(remln>0):
|
||||
ws.shuffle(repl)
|
||||
ws.sbox(d0x6a06ea70,d0x6a0dab50)
|
||||
ws.sbox(d0x6a073a70,d0x6a0dab50)
|
||||
ws.shuffle(repl)
|
||||
ws.exlookup(d0x6a072a70)
|
||||
dat=ws.mask(st[sto:sto+16])
|
||||
out+=dat
|
||||
sto+=16
|
||||
remln-=16;
|
||||
return bytes(out)
|
||||
|
||||
def process_V1031(st):
|
||||
#d53efea7fdd0fda3e1e0ebbae87cad0e8f5ef413c471c3ae81f39222a9ec8b8ed582e045918c
|
||||
ws=workspace([0x06,0x18,0x60,0x68,0x3b,0x62,0x3e,0x3c,0x06,0x50,0x71,0x52,0x02,0x5a,0x63,0x03])
|
||||
repl=[0,5,10,15,4,9,14,3,8,13,2,7,12,1,6,11]
|
||||
remln=len(st)
|
||||
sto=0
|
||||
out=[]
|
||||
while(remln>0):
|
||||
ws.shuffle(repl)
|
||||
ws.sbox(d0x6a0797c0,d0x6a0dab50,[3])
|
||||
ws.sbox(d0x6a07e7c0,d0x6a0dab50,[3])
|
||||
ws.shuffle(repl)
|
||||
ws.sbox(d0x6a0797c0,d0x6a0dab50,[3])
|
||||
ws.sbox(d0x6a07e7c0,d0x6a0dab50,[3])
|
||||
ws.exlookup(d0x6a07d7c0)
|
||||
dat=ws.mask(st[sto:sto+16])
|
||||
out+=dat
|
||||
sto+=16
|
||||
remln-=16
|
||||
#break
|
||||
return bytes(out)
|
||||
|
||||
def process_V2069(st):
|
||||
#8e6196d754a304c9354e91b5d79f07b048026d31c7373a8691e513f2c802c706742731caa858
|
||||
ws=workspace([0x79,0x0d,0x12,0x08,0x66,0x77,0x2e,0x5b,0x02,0x09,0x0a,0x13,0x11,0x0c,0x11,0x62])
|
||||
repl=[0,5,10,15,4,9,14,3,8,13,2,7,12,1,6,11]
|
||||
remln=len(st)
|
||||
sto=0
|
||||
out=[]
|
||||
while(remln>0):
|
||||
ws.sbox(d0x6a084498,d0x6a0dab50,[2])
|
||||
ws.shuffle(repl)
|
||||
ws.sbox(d0x6a089498,d0x6a0dab50,[2])
|
||||
ws.sbox(d0x6a089498,d0x6a0dab50,[2])
|
||||
ws.sbox(d0x6a084498,d0x6a0dab50,[2])
|
||||
ws.shuffle(repl)
|
||||
ws.exlookup(d0x6a088498)
|
||||
dat=ws.mask(st[sto:sto+16])
|
||||
out+=dat
|
||||
sto+=16
|
||||
remln-=16
|
||||
return bytes(out)
|
||||
|
||||
|
||||
def process_V9041(st):
|
||||
#11f7db074b24e560dfa6fae3252b383c3b936e51f6ded570dc936cb1da9f4fc4a97ec686e7d8
|
||||
ws=workspace([0x49,0x0b,0x0e,0x3b,0x19,0x1a,0x49,0x61,0x10,0x73,0x19,0x67,0x5c,0x1b,0x11,0x21])
|
||||
repl=[0,5,10,15,4,9,14,3,8,13,2,7,12,1,6,11]
|
||||
remln=len(st)
|
||||
sto=0
|
||||
out=[]
|
||||
while(remln>0):
|
||||
ws.sbox(d0x6a094170,d0x6a0dab50,[1])
|
||||
ws.shuffle(repl)
|
||||
ws.shuffle(repl)
|
||||
ws.sbox(d0x6a08f170,d0x6a0dab50,[1])
|
||||
ws.sbox(d0x6a08f170,d0x6a0dab50,[1])
|
||||
ws.sbox(d0x6a094170,d0x6a0dab50,[1])
|
||||
|
||||
ws.exlookup(d0x6a093170)
|
||||
dat=ws.mask(st[sto:sto+16])
|
||||
out+=dat
|
||||
sto+=16
|
||||
remln-=16
|
||||
#break
|
||||
return bytes(out)
|
||||
|
||||
def process_V3646(st):
|
||||
#d468aa362b44479282291983243b38197c4b4aa24c2c58e62c76ec4b81e08556ca0c54301664
|
||||
ws=workspace([0x0a,0x36,0x3e,0x29,0x4e,0x02,0x18,0x38,0x01,0x36,0x73,0x13,0x14,0x1b,0x16,0x6a])
|
||||
repl=[0,5,10,15,4,9,14,3,8,13,2,7,12,1,6,11]
|
||||
remln=len(st)
|
||||
sto=0
|
||||
out=[]
|
||||
while(remln>0):
|
||||
ws.shuffle(repl)
|
||||
ws.sbox(d0x6a099e48,d0x6a0dab50,[2,3])
|
||||
ws.sbox(d0x6a09ee48,d0x6a0dab50,[2,3])
|
||||
ws.sbox(d0x6a09ee48,d0x6a0dab50,[2,3])
|
||||
ws.shuffle(repl)
|
||||
ws.sbox(d0x6a099e48,d0x6a0dab50,[2,3])
|
||||
ws.sbox(d0x6a099e48,d0x6a0dab50,[2,3])
|
||||
ws.shuffle(repl)
|
||||
ws.sbox(d0x6a09ee48,d0x6a0dab50,[2,3])
|
||||
ws.exlookup(d0x6a09de48)
|
||||
dat=ws.mask(st[sto:sto+16])
|
||||
out+=dat
|
||||
sto+=16
|
||||
remln-=16
|
||||
return bytes(out)
|
||||
|
||||
|
||||
def process_V6052(st):
|
||||
#d683c8c4e4f46ae45812196f37e218eabce0fae08994f25fabb01d3e569b8bf3866b99d36f57
|
||||
ws=workspace([0x5f,0x0d,0x01,0x12,0x5d,0x5c,0x14,0x2a,0x17,0x69,0x14,0x0d,0x09,0x21,0x1e,0x3b])
|
||||
repl=[0,5,10,15,4,9,14,3,8,13,2,7,12,1,6,11]
|
||||
remln=len(st)
|
||||
sto=0
|
||||
out=[]
|
||||
while(remln>0):
|
||||
ws.shuffle(repl)
|
||||
ws.sbox(d0x6a0a4b20,d0x6a0dab50,[1,3])
|
||||
ws.shuffle(repl)
|
||||
ws.sbox(d0x6a0a4b20,d0x6a0dab50,[1,3])
|
||||
ws.sbox(d0x6a0a9b20,d0x6a0dab50,[1,3])
|
||||
ws.shuffle(repl)
|
||||
ws.sbox(d0x6a0a9b20,d0x6a0dab50,[1,3])
|
||||
ws.sbox(d0x6a0a9b20,d0x6a0dab50,[1,3])
|
||||
ws.sbox(d0x6a0a4b20,d0x6a0dab50,[1,3])
|
||||
|
||||
ws.exlookup(d0x6a0a8b20)
|
||||
dat=ws.mask(st[sto:sto+16])
|
||||
out+=dat
|
||||
sto+=16
|
||||
remln-=16
|
||||
return bytes(out)
|
||||
|
||||
def process_V9479(st):
|
||||
#925635db434bccd3f4791eb87b89d2dfc7c93be06e794744eb9de58e6d721e696980680ab551
|
||||
ws=workspace([0x65,0x1d,0x19,0x7c,0x09,0x79,0x1d,0x69,0x7c,0x4e,0x13,0x0e,0x04,0x1b,0x6a,0x3c ])
|
||||
repl=[0,5,10,15,4,9,14,3,8,13,2,7,12,1,6,11]
|
||||
remln=len(st)
|
||||
sto=0
|
||||
out=[]
|
||||
while(remln>0):
|
||||
ws.sbox(d0x6a0af7f8,d0x6a0dab50,[1,2,3])
|
||||
ws.sbox(d0x6a0af7f8,d0x6a0dab50,[1,2,3])
|
||||
ws.sbox(d0x6a0b47f8,d0x6a0dab50,[1,2,3])
|
||||
ws.sbox(d0x6a0af7f8,d0x6a0dab50,[1,2,3])
|
||||
ws.shuffle(repl)
|
||||
ws.sbox(d0x6a0b47f8,d0x6a0dab50,[1,2,3])
|
||||
ws.shuffle(repl)
|
||||
ws.shuffle(repl)
|
||||
ws.sbox(d0x6a0b47f8,d0x6a0dab50,[1,2,3])
|
||||
ws.exlookup(d0x6a0b37f8)
|
||||
|
||||
dat=ws.mask(st[sto:sto+16])
|
||||
out+=dat
|
||||
sto+=16
|
||||
remln-=16
|
||||
return bytes(out)
|
||||
|
||||
def process_V9888(st):
|
||||
#54c470723f8c105ba0186b6319050869de673ce31a5ec15d4439921d4cd05c5e860cb2a41fea
|
||||
ws=workspace([0x3f,0x17,0x79,0x69,0x24,0x6b,0x37,0x50,0x63,0x09,0x45,0x6f,0x0c,0x07,0x07,0x09])
|
||||
repl=[0,5,10,15,4,9,14,3,8,13,2,7,12,1,6,11]
|
||||
remln=len(st)
|
||||
sto=0
|
||||
out=[]
|
||||
while(remln>0):
|
||||
ws.sbox(d0x6a0ba4d0,d0x6a0dab50,[1,2])
|
||||
ws.sbox(d0x6a0bf4d0,d0x6a0dab50,[1,2])
|
||||
ws.sbox(d0x6a0bf4d0,d0x6a0dab50,[1,2])
|
||||
ws.sbox(d0x6a0ba4d0,d0x6a0dab50,[1,2])
|
||||
ws.shuffle(repl)
|
||||
ws.shuffle(repl)
|
||||
ws.shuffle(repl)
|
||||
ws.sbox(d0x6a0bf4d0,d0x6a0dab50,[1,2])
|
||||
ws.sbox(d0x6a0ba4d0,d0x6a0dab50,[1,2])
|
||||
ws.exlookup(d0x6a0be4d0)
|
||||
dat=ws.mask(st[sto:sto+16])
|
||||
out+=dat
|
||||
sto+=16
|
||||
remln-=16
|
||||
return bytes(out)
|
||||
|
||||
def process_V4648(st):
|
||||
#705bd4cd8b61d4596ef4ca40774d68e71f1f846c6e94bd23fd26e5c127e0beaa650a50171f1b
|
||||
ws=workspace([0x16,0x2b,0x64,0x62,0x13,0x04,0x18,0x0d,0x63,0x25,0x14,0x17,0x0f,0x13,0x46,0x0c])
|
||||
repl=[0,5,10,15,4,9,14,3,8,13,2,7,12,1,6,11]
|
||||
remln=len(st)
|
||||
sto=0
|
||||
out=[]
|
||||
while(remln>0):
|
||||
ws.sbox(d0x6a0ca1a8,d0x6a0dab50,[1,3])
|
||||
ws.shuffle(repl)
|
||||
ws.sbox(d0x6a0ca1a8,d0x6a0dab50,[1,3])
|
||||
ws.sbox(d0x6a0c51a8,d0x6a0dab50,[1,3])
|
||||
ws.sbox(d0x6a0ca1a8,d0x6a0dab50,[1,3])
|
||||
ws.sbox(d0x6a0c51a8,d0x6a0dab50,[1,3])
|
||||
ws.sbox(d0x6a0c51a8,d0x6a0dab50,[1,3])
|
||||
ws.shuffle(repl)
|
||||
ws.shuffle(repl)
|
||||
ws.exlookup(d0x6a0c91a8)
|
||||
dat=ws.mask(st[sto:sto+16])
|
||||
out+=dat
|
||||
sto+=16
|
||||
remln-=16
|
||||
return bytes(out)
|
||||
|
||||
def process_V5683(st):
|
||||
#1f5af733423e5104afb9d5594e682ecf839a776257f33747c9beee671c57ab3f84943f69d8fd
|
||||
ws=workspace([0x7c,0x36,0x5c,0x1a,0x0d,0x10,0x0a,0x50,0x07,0x0f,0x75,0x1f,0x09,0x3b,0x0d,0x72])
|
||||
repl=[0,5,10,15,4,9,14,3,8,13,2,7,12,1,6,11]
|
||||
remln=len(st)
|
||||
sto=0
|
||||
out=[]
|
||||
while(remln>0):
|
||||
ws.sbox(d0x6a0d4e80,d0x6a0dab50,[])
|
||||
ws.shuffle(repl)
|
||||
ws.sbox(d0x6a0cfe80,d0x6a0dab50,[])
|
||||
ws.sbox(d0x6a0d4e80,d0x6a0dab50,[])
|
||||
ws.sbox(d0x6a0cfe80,d0x6a0dab50,[])
|
||||
ws.sbox(d0x6a0d4e80,d0x6a0dab50,[])
|
||||
ws.shuffle(repl)
|
||||
ws.sbox(d0x6a0cfe80,d0x6a0dab50,[])
|
||||
ws.shuffle(repl)
|
||||
ws.exlookup(d0x6a0d3e80)
|
||||
dat=ws.mask(st[sto:sto+16])
|
||||
out+=dat
|
||||
sto+=16
|
||||
remln-=16
|
||||
return bytes(out)
|
||||
|
||||
|
||||
# def a2hex(arr):
|
||||
# ax=[]
|
||||
# ha="0123456789abcdef"
|
||||
# for a in arr:
|
||||
# if a<0: a=256+a
|
||||
# ax.append(ha[(a>>4)]+ha[a%16])
|
||||
# return "".join(ax)
|
||||
#
|
||||
# def memhex(adr,sz):
|
||||
# emu=EmulatorHelper(currentProgram)
|
||||
# arr=emu.readMemory(getAddress(adr),sz)
|
||||
# return a2hex(arr)
|
||||
#
|
||||
|
||||
|
||||
|
||||
|
||||
# obfuscate shared secret according to the VoucherEnvelope version
|
||||
def obfuscate(secret, version):
|
||||
if version == 1: # v1 does not use obfuscation
|
||||
@@ -980,7 +1339,12 @@ class DrmIonVoucher(object):
|
||||
_assert(False, "Unknown lock parameter: %s" % param)
|
||||
|
||||
|
||||
sharedsecrets = [obfuscate(shared, self.version),obfuscate2(shared, self.version),obfuscate3(shared, self.version)]
|
||||
# i know that version maps to scramble pretty much 1 to 1, but there was precendent where they changed it, so...
|
||||
sharedsecrets = [obfuscate(shared, self.version),obfuscate2(shared, self.version),obfuscate3(shared, self.version),
|
||||
process_V9708(shared), process_V1031(shared), process_V2069(shared), process_V9041(shared),
|
||||
process_V3646(shared), process_V6052(shared), process_V9479(shared), process_V9888(shared),
|
||||
process_V4648(shared), process_V5683(shared)]
|
||||
|
||||
decrypted=False
|
||||
ex=None
|
||||
for sharedsecret in sharedsecrets:
|
||||
@@ -989,7 +1353,13 @@ class DrmIonVoucher(object):
|
||||
try:
|
||||
b = aes.decrypt(self.ciphertext)
|
||||
b = pkcs7unpad(b, 16)
|
||||
self.drmkey = BinaryIonParser(BytesIO(b))
|
||||
addprottable(self.drmkey)
|
||||
|
||||
_assert(self.drmkey.hasnext() and self.drmkey.next() == TID_LIST and self.drmkey.gettypename() == "com.amazon.drm.KeySet@1.0",
|
||||
"Expected KeySet, got %s" % self.drmkey.gettypename())
|
||||
decrypted=True
|
||||
|
||||
print("Decryption succeeded")
|
||||
break
|
||||
except Exception as ex:
|
||||
@@ -997,14 +1367,6 @@ class DrmIonVoucher(object):
|
||||
if not decrypted:
|
||||
raise ex
|
||||
|
||||
sharedsecret = obfuscate(shared, self.version)
|
||||
|
||||
self.drmkey = BinaryIonParser(BytesIO(b))
|
||||
addprottable(self.drmkey)
|
||||
|
||||
_assert(self.drmkey.hasnext() and self.drmkey.next() == TID_LIST and self.drmkey.gettypename() == "com.amazon.drm.KeySet@1.0",
|
||||
"Expected KeySet, got %s" % self.drmkey.gettypename())
|
||||
|
||||
self.drmkey.stepin()
|
||||
while self.drmkey.hasnext():
|
||||
self.drmkey.next()
|
||||
|
||||
5771
DeDRM_plugin/kfxtables.py
Normal file
5771
DeDRM_plugin/kfxtables.py
Normal file
File diff suppressed because it is too large
Load Diff
@@ -3,6 +3,8 @@ DeDRM tools for ebooks
|
||||
|
||||
This is a fork of Apprentice Harper's version of the DeDRM tools. Apprentice Harper said that the original version of the plugin [is no longer maintained](https://github.com/apprenticeharper/DeDRM_tools#no-longer-maintained), so I've taken over, merged a bunch of open PRs, and added a ton more features and bugfixes.
|
||||
|
||||
The latest stable (released) version is v10.0.3 which [can be downloaded here](https://github.com/noDRM/DeDRM_tools/releases/tag/v10.0.3). The latest `master` build (will be automatically updated with every code change, may be unstable) [can be found here](https://github.com/noDRM/DeDRM_tools/releases/tag/autorelease).
|
||||
|
||||
Take a look at [the CHANGELOG](https://github.com/noDRM/DeDRM_tools/blob/master/CHANGELOG.md) to see a list of changes since the last version by Apprentice Harper (v7.2.1). This plugin will start with version v10.0.0.
|
||||
|
||||
The v10.0.0 versions of this plugin should both work with Calibre 5.x (Python 3) as well as Calibre 4.x and lower (Python 2). If you encounter issues with this plugin in Calibre 4.x or lower, please open a bug report.
|
||||
|
||||
Reference in New Issue
Block a user