作者cassine (Savannah)
看板Modchip
标题Re: [PS3 ] 重编译启动合法持有的NP-DRM游戏
时间Fri Oct 14 17:30:37 2011
ps3hax.net论坛上有关於NP-DRM版权保护机制的技术讨论,有兴趣的可以看下去
http://www.ps3hax.net/showthread.php?t=28303
THIS DOES NOT ALLOW TO OBTAIN 3.60+ keys
以下的讨论跟获取 3.60+的解密金钥无关
On NPDRM self decryption all the security levels of the PS3 are
involved: user space (vsh), kernel space(lv2), hypervisor( lv1) and
isolated SPU (metldr + appldr)
关於NP-DRM保护的解密,可以说整台主机提供的加解密机制都用到了,包括使用
者介面的vsh.self、系统核心相关的lv2.self 、管家婆相关的 lv1.self,还有
独立在 SPU里头的metldr与appldr。
The process start on vsh.elf...
所以让我们从vsh.self开始
VSH:
vsh.self部份:
Once the vsh detects that user is trying to start a self, it looks
for the appinfo header type. If the type is 8, then the control
digest element type 3 (NPD element) is located. From this NPD header
the vsh gets the license type (free, local or network license).
当vsh.self侦测到使用者要载入一个加密的self执行档时,它会先去查看档头的
标记,读取相关加密资讯(版本、方式等),如果加密类别的标记是 8,就代表
是一个NP-DRM加密的程式,所以继续读取NP-DRM的讯息,取得授权资讯(免费、
可以在本机执行或仅能连网执行)。
If a free content(type 3) is detected then a generic klicense will be
use for further steps (go to LV2). That klicensee is already public
(see geohot npdrm_omac_key_1).
如果授权是免费(授权类别 3),那就会直接引用通用的klicense,然後直接丢
给lv2.self去继续解密。通用的klicense拜geohot所赐,早已经广为人知。请参
照geohot的npdrm_omac_key_1。
However if a paid content is to be loaded the vsh loads the act.dat
and the rif associated to the content (if local it will locate a file
with the same titleid on NPD element, if remote it will download to
vsh process memory)
如果是付费授权,则vsh.self还会继续载入 act.dat档案与 rif档案(如果是本
机授权,则会载入一个有相同titleid 的档案,若是远端授权,则会将档案自
PSN主机下载後存在记忆体中)
Then the signature is checked (last 0x28 bytes of both RIF and
act.dat). The curves used are on vsh.self. It is a 3 element table,
having the first curve nulled. The curve index for rif/act is 2. The
curve values are negated as in the apploader and has the following
structure
最後会检查数位签章( act.dat与 rif档案尾巴长度为0x28的资讯),曲线类别
都存放在vsh.self中〔译注:应指椭圆曲线加密的曲线类别〕,此为一个三个元
素的表格,第一个曲线为空。 rif/act所使用的曲线索引号为 2。如同在appldr
中,曲线的值是无意义并具有以下结构:〔不是很懂这段话的意思〕
struct curve {
uint8_t p[0x14];
uint8_t a[0x14];
uint8_t b[0x14];
uint8_t N[0x14];
uint8_t Gx[0x14];
uint8_t Gy[0x14];
};
If the curve checks then vsh will process the rif:
检查完曲线後vsh.self会继续检查 rif与 act.dat档案,结构如下:
struct rif {
uint8_t unk1[0x10]; //version, license type and user number
uint8_t titleid[0x30]; //Content ID
uint8 padding[0xC]; //Padding for randomness
uint32_t actDatIndex; //Key index on act.dat between 0x00 and 0x7F
uint8 key[0x10]; //encrypted klicensee
uint64_t unk2; //timestamp??
uint64_t unk3; //Always 0
uint8_t rs[0x28];
};
struct ACTDAT {
uint8_t unk1[0x10]; //Version, User number
uint8_t keyTable[0x800]; //Key Table
......
uint8_t signature[0x28];
};
Using the RIF_KEY it will obtain the actdatIndex:
然後使用rifKey去解密 act.dat里面加密的部份:
AES_KEY rifKey;
int result = AES_set_decrypt_key(RIF_KEY, 0x80, &rifKey);
AES_decrypt(&rif->padding, &rif->padding, &rifKey);
And finally having the actDat key index the execution pass to LV2
syscall 471
解密後会得到actDat的金钥索引,然後传给 LV2 syscall 471。
LV2
lv2.self的部份:
Lv2 is accessed using syscall471 which haves the following syntax:
lv2.self将相关参数用以下格式传给syscall 471:
int syscall_471(uint32_t type, char* titleID, void* klicensee,
uint8_t* actdat, uint8_t* rif, int32_t licenseType,
uint8_t* magicVersion);
The function has different parameters depending if the content is
debug, free or paid:
依照内容是除错授权、免费授权或是付费授权,此一函式有不同的参数。
FREE: syscall471(npd.type, &npd.titleID, freeklicensee, NULL, NULL,
npd.license, &npd);
免费授权的参数。
PAID: syscall471(npd.type, &npd.titleID, NULL,
&actdat.keyTable[rif.actDatIndex*0x10], &rif.key,
npd.license, &npd);
付费授权的参数。
The lv2 keeps a memory table with contentID and the associated key.
When it receives a free content (r5 is not null) then copies the
titleID and the klicensee to the table. For a paid content the
rif.key is converted to the klicensee using:
lv2.self会将 contentID与相关的金钥用表格的形式存在记忆体中,若是免费的
内容(r5非空),则把titleID与klicense 填入表格。若是付费的内容,则会将
rif.key 转换成klicense的形式。
AES_KEY IDPSKey, ConstKey, ActDatKey;
uint8_t encrConst[0x10];
uint8_t decryptedActDat[0x10];
uint8_t klicensee[0x10];
int result = AES_set_encrypt_key(&IDPSVariation, 0x80, &IDPSKey);
AES_encrypt(&CONSTACTDAT, &encrConst, &IDPSKey);
result = AES_set_decrypt_key(&encrConst,0x80,&ConstKey);
AES_decrypt(actDat,&decryptedActDat,&ConstKey);
result = AES_set_decrypt_key(&decryptedActDat,0x80,&ActDatKey);
AES_decrypt(rif,&klicensee,&ActDatKey);
where CONSTACTDAT is a constant value on lv2, IDPSVaritaion appears
to be IDPS (not checked but DRM_Manager_initialize (see
graf_chokolo's "bible") to something with the same structure), actdat
are the 0x10bytes selected by rif keyIndex, and rif is rif.key (bytes
0x50-0x5f).
其中CONSTACTDAT是lv2 里头的一个常数值、IDPSVariation显然就是主机的IDPS
讯息(虽然没用到,但DRM_Manager_initialize还是有载入,请参阅graf_chokolo
的 PS3百科)、actdat是一个透过rif 金钥索引指定,长度为0x10的变数、 rif
自然就是 rif.key(里头位址为0x50到0x5f的部份)
Once transformed it is stored on memory table...
转换完成後,就会存在记忆体的表格里面……。
I haven't check further steps on vsh nor lv2 so perhaps there are
further transformations on the paid case (NOT FOR THE FREE AS I HAVE
DECRYPTED THOSE) so we are jumping directly to the appldr
在vsh 跟lv2 更详细的解密步骤我就没仔细研究了,也许付费的场合中还有更多
的转换(在免费的场合没见到,因为我已经把免费的都解密了),既然如此,就
让我们进到appldr这边。
AppLdr
As you can see from graf_chokolo payloads a parameter is passed on
spu_args.field60. That parameter is the previously stored klicensee.
如果你有仔细研究过graf_chokolo的酬载〔译注:graf_chokolo曾经利用3.41版
韧体的漏洞,用PSGroove工具透过自己的酬载把所有的 PSN游戏全部解密〕,会
发现他的程式送了一个东西到spu_args.field60去,这个东西就是前一步骤中得
到的klicense。
However this key must be transformed (again) even for the free case.
The transformation is:
然而,这个金钥还得再度转换,就算是免费授权的也一样,转换方式如下:
uint8_t decryptedKLicensee[0x10]
AES_KEY KLicenseeKey
int result =
AES_set_decrypt_key(&KLicenseeDecryptKey,0x80,&KLICENSEEKEY);
AES_decrypt(klicensee,&decryptedKLicensee,&KLicenseeKey);
EY is another key located inside the apploader and klicensee is the
parameter.
其中的EY是appldr里头的另一个金钥。
Then we can finally remove the NPDRM layer using:
所以我们就可以移除整个NP-DRM的防护,步骤如下:
AES_KEY key;
uint8_t iv[0x10];
memset(&iv[0],0,0x10);
int result = AES_set_decrypt_key(&KLicenseeDecryptKey,0x80,&key);
AES_cbc_encrypt(self + self->metaoffset + 0x20, self +
self->metaoffset + 0x20,0x40,&key,&iv,0);
Once that layer is removed we proceed as normal:
一旦NP-DRM防护移除後,事情就很简单了:
-Decrypt using AESCBC256 with the NPDRM keys to obtain the metadata
keys
使用NP-DRM解密金钥搭配AESCBC256演算法解密获得metadata金钥
-Decrypt using AESCTR128 the data sha, hmac, iv keys
利用data sha、hmac、iv金钥透过AESCTR128演算法解密
-Decrypt the data.
解密所有的资料。
PD: I WILL NOT PROVIDE ANY OF THE KEYS MENTIONED ABOVE
注意:本人将不提供相关金钥。
Credits to euss (documentation, keys and testing),
mallory(testing,code), jester(testing)
致谢:euss负责整个文件结构、金钥与测试
mallory 负责测试与写程式
jester负责测试
******
本文转录前请先徵得本人同意
--
○ ____ _ _ _ _ ____ _ _ ____ _____ ____
。 ★(_ _)( \( )( \/ )( ___)( \( )(_ _)( _ )( _ \
o _)(_ ) ( \ / )__) ) ( )( )(_)( ) / ● ‧
(____)(_)\_) \/ (____)(_)\_) (__) (_____)(_)\_) ★
o
--
※ 发信站 :批踢踢实业坊(ptt.cc)
◆ From: 140.120.31.137
1F:推 fuj:没想到连中文也看不懂 10/14 17:51
2F:推 ccpz:"curve values are negated as" 这里 negated 是说做 ! 10/14 22:02
3F:→ ccpz:也就是每一个位元 0->1, 1->0 10/14 22:02
4F:推 ccpz:"last 0x28 bytes of both RIF" 这是嘬档案尾 0x28 个 byte 10/14 22:06
5F:→ ccpz:0x28 是 16 进位, 也就是档案尾的 40 byte 10/14 22:07
6F:→ ccpz:应该是这样子吧 10/14 22:08