Compare commits

...

35 Commits
v1.9 ... main

Author SHA1 Message Date
Li
33f288f673 Merge pull request 'mention the no-root thingy' (#3) from randomhuman-patch-1 into main
Reviewed-on: #3
2024-06-06 02:42:52 +00:00
912ee1aae4 Update readme.md 2024-06-06 02:42:24 +00:00
d23949671c Update readme.md 2024-06-06 02:40:33 +00:00
b113de0985 mention the no-root thingy
why do you make me do these things at 3 in the fucking morning
2024-06-04 09:31:28 +00:00
Li
01d3f6bf0f Update readme.md 2024-06-01 09:10:52 +00:00
Li
3a0ff41699 update native modules and stuff 2024-06-01 20:31:41 +12:00
ddd8055465 Update readme.md 2024-06-01 08:30:47 +00:00
Li
c6b2398a36 Merge pull request 'major changes to the readme, add new category' (#2) from randomhuman-patch-1 into main
Reviewed-on: #2
2024-05-31 01:36:21 +00:00
44fc4cbb7b major changes to the readme, add new category
made *major* changes to the readme.md, so putting it in a pull request instead of directly commiting like i always would otherwise
added a new section to show which patches exist, and what they actually do
2024-05-31 01:33:37 +00:00
Li
aecd07844d remove uneeeded imports 2024-05-27 16:05:25 +12:00
Li
3c6499b247 refactor more? 2024-05-27 16:03:36 +12:00
Li
333250c416 Fix shared prefs generation 2024-05-27 15:21:05 +12:00
Li
0bbbb239ef Refactor like, alot 2024-05-27 15:17:31 +12:00
Li
f087d5160c Update to v2.0 2024-05-27 02:50:39 +12:00
Li
3cd316a805 Update readme 2024-05-26 11:11:48 +12:00
Li
6e597b9063 Merge branch 'main' of https://silica.codes/Li/NoPsmDrm-Android 2024-05-26 11:10:04 +12:00
Li
e6bda25715 Bypass PS1 certified check (xposed) 2024-05-26 11:09:49 +12:00
d1a07e035d Update readme.md 2024-05-24 19:18:46 +00:00
Li
8e6f8b09b1 fix busyboxs 2024-05-24 18:44:45 +12:00
Li
5579925e66 Merge branch 'main' of https://silica.codes/Li/NoPsmDrm-Android 2024-05-24 18:40:37 +12:00
Li
3366036bf0 Create xposed module to hook psm network info 2024-05-24 18:37:11 +12:00
Li
a6dc9fbd93 oops forgot this 2024-05-20 09:07:01 +00:00
Li
83b155437f Merge branch 'main' of https://silica.codes/Li/NoPsmDrm-Android 2024-05-20 14:37:32 +12:00
Li
6fcf0643c7 supress warnings in gradle 2024-05-20 14:37:18 +12:00
Li
5dfdea82d0 Update readme.md 2024-05-20 02:11:46 +00:00
d3838fdb28 Update readme.md 2024-05-19 23:25:22 +00:00
Li
3305933dc9 Update readme.md 2024-05-19 23:18:41 +00:00
Li
d904e40b77 Update readme.md 2024-05-19 23:18:09 +00:00
Li
a416efaebc Fix some issues, skip failed to download message in PSM if zpak exists .. 2024-05-20 10:59:34 +12:00
Li
513f30b1da aa 2024-05-19 18:30:52 +12:00
Li
584e6c913d Remove AndroidX 2024-05-19 17:59:42 +12:00
Li
6e157330cf Fix crashing (temporary fix) 2024-05-19 15:29:12 +12:00
Li
0fce254917 catch more possible errors from PSM 2024-05-19 15:23:00 +12:00
Li
f821147c21 Make game start even if ZPAK download fails.: 2024-05-19 14:18:57 +12:00
Li
f7555574d6 Make np ticket generation more correct -ty olebeck 2024-05-19 13:07:40 +12:00
59 changed files with 1733 additions and 782 deletions

View File

@ -1 +1 @@
nopsmdrm
nopssdrm

View File

@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="UNCHECKED_WARNING" enabled="false" level="WARNING" enabled_by_default="false" />
</profile>
</component>

177
LICENSE Normal file
View File

@ -0,0 +1,177 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS

View File

@ -4,16 +4,16 @@ plugins {
android {
namespace 'com.psmreborn.nopsmdrm'
//noinspection GradleDependency were targeting the xperia play
//noinspection GradleDependency needs to work properly on android 2.x
compileSdk 10
defaultConfig {
applicationId "com.psmreborn.nopsmdrm"
minSdk 10
//noinspection ExpiredTargetSdkVersion dont care about google play
//noinspection ExpiredTargetSdkVersion app is not distributed on google play -- this app breaks all its rules anyway
targetSdk 23
versionCode 9
versionName "1.9"
versionCode 200
versionName "2.0"
}
buildTypes {
@ -25,10 +25,20 @@ android {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
applicationVariants.configureEach { variant ->
variant.outputs.configureEach {
def versionName = variant.versionName
outputFileName = "${applicationName}.apk"
}
}
}
dependencies {
implementation project(':libsuperuser')
implementation project(':libABX')
implementation 'yuv.pink:npticket:1.6'
//noinspection GradleDependency new version doesnt support xperia play.
compileOnly 'de.robv.android.xposed:api:53'
//noinspection GradleDependency new version doesnt support xperia play.
implementation 'com.android.support:support-core-utils:25.0.0'
}

View File

@ -20,18 +20,38 @@
<application
android:allowBackup="true"
android:icon="@drawable/app_icon"
android:label="@string/name_nopsmdrm">
<activity android:name="com.psmreborn.nopsmdrm.MainActivity">
android:label="@string/app_name">
<activity android:name="com.psmreborn.nopsmdrm.MainActivity" android:label="@string/name_nopsmdrm">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:launchMode="singleTop" android:name="com.psmreborn.nops1drm.LicenseCheckActivity" android:label="@string/name_nops1drm" android:icon="@drawable/nops1drm_icon" android:screenOrientation="landscape">
<activity android:launchMode="singleTop" android:name="com.psmreborn.nops1drm.LicenseCheckActivity" android:label="@string/name_nops1drm_ticket" android:icon="@drawable/nops1drm_ticket_icon" android:screenOrientation="landscape">
<intent-filter>
<action android:name="com.playstation.android.intent.action.CHECK_ENTITLEMENT"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
<activity android:name="com.psmreborn.nops1drm.DownloadActivity" android:label="@string/name_nops1drm_update" android:icon="@drawable/nops1drm_update_icon" android:screenOrientation="landscape" android:windowSoftInputMode="stateAlwaysHidden">
<intent-filter>
<action android:name="com.playstation.android.intent.action.DOWNLOAD_ZPAK"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
<meta-data
android:name="xposedmodule"
android:value="true" />
<meta-data
android:name="xposeddescription"
android:value="Java patches to PSM.apk" />
<meta-data
android:name="xposedminversion"
android:value="53" />
<meta-data
android:name="xposedscope"
android:resource="@array/scope" />
</application>
</manifest>

View File

@ -0,0 +1 @@
com.psmreborn.xposed.JavaPatch

View File

@ -0,0 +1,142 @@
package com.psmreborn.nops1drm;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.util.Log;
import com.psmreborn.nopsmdrm.MainActivity;
import com.psmreborn.nopsmdrm.R;
import com.psmreborn.shared.Downloader;
import com.psmreborn.shared.Logger;
import java.io.File;
public class DownloadActivity extends Activity {
private static final int RESPONSE_CODE = 20000305;
private String entitlementId = null;
private String appName = null;
private boolean forceDownload = false;
private String skuId = null;
private String returnToActivity = null;
private String returnToPackage = null;
private String zpakLocation = null;
@SuppressLint("WrongConstant")
public void respond(int resp){
Log.i("ZpakDl", "Responding with response code: "+resp);
Intent resIntent = new Intent();
this.setResult(resp, resIntent);
this.finish();
}
private void forwardIntentToPsm(){
Log.i("ZpakDl", "Forwarding intent to PSM ...");
Intent respondIntent = new Intent("com.playstation.android.intent.action.DOWNLOAD_ZPAK");
respondIntent.putExtra("entitlement_id", this.entitlementId);
respondIntent.putExtra("app_name", this.appName);
respondIntent.putExtra("force_download", this.forceDownload);
if(this.returnToPackage != null)
respondIntent.putExtra("return_to_package", this.returnToPackage);
if(this.returnToActivity != null)
respondIntent.putExtra("return_to_activity", this.returnToActivity);
if(this.skuId != null)
respondIntent.putExtra("sku_id", this.skuId);
respondIntent.setPackage(this.getResources().getString(R.string.psm_app_package_id));
startActivityForResult(respondIntent, RESPONSE_CODE);
}
private boolean checkZpakExist(){
Log.i("ZpakDl", "Checking for zpak file.");
File zpakLoc = new File(this.zpakLocation);
if(!zpakLoc.exists()) return false;
String[] zpaks = zpakLoc.list();
if(zpaks == null) return false;
for(String zpak : zpaks){
Log.i("ZpakDl", "Chceking file: "+zpak);
if(zpak.endsWith(".zpak")){
return true;
}
}
return false;
}
@Override
protected void onActivityResult(int res, int res_code, Intent intent) {
if(res == RESPONSE_CODE) {
Logger.logText( "RES", String.valueOf(res_code));
if(res_code == 0) {
if(checkZpakExist()){
Log.i("ZpakDownload", "Update failed, faking sucess code.");
res_code = -1;
}
}
respond(res_code);
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = this.getIntent();
this.entitlementId = intent.getStringExtra("entitlement_id");
this.appName = intent.getStringExtra("app_name");
this.returnToPackage = intent.getStringExtra("return_to_package");
this.returnToActivity = intent.getStringExtra("return_to_activity");
this.forceDownload = intent.getBooleanExtra("force_download", false);
this.skuId = intent.getStringExtra("sku_id");
this.zpakLocation = new File(new File(new File(new File(new File(Environment.getExternalStorageDirectory(), "Android"), "data"), this.returnToPackage), "files"), "content").getAbsolutePath();
Logger.logText("entitlement_id", this.entitlementId);
Logger.logText("app_name", this.appName);
Logger.logText("return_to_package", this.returnToPackage);
Logger.logText("return_to_activity", this.returnToActivity);
Logger.logText("force_download", String.valueOf(this.forceDownload));
Logger.logText("sku_id", this.skuId);
Logger.logText("zpak_location", this.zpakLocation);
Handler handler = new Handler(this.getMainLooper());
new Thread(() -> {
if(!checkZpakExist()){
handler.post(() -> {
new AlertDialog.Builder(this)
.setTitle("zPAK not found!")
.setMessage("No zPAK was found in:\n\""+this.zpakLocation+"\"\nI can start PSM to download it\nOr i could just tell "+this.appName+" to completely ignore it\n(this will probably crash the game)")
.setCancelable(false)
.setPositiveButton("Launch PSM.", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
forwardIntentToPsm();
}
})
.setNegativeButton("Ignore it.", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
respond(-1);
}
}).show();
});
}
else{
handler.post(() -> {
respond(-1);
});
}
}).start();
}
}

View File

@ -1,21 +1,28 @@
package com.psmreborn.nops1drm;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import com.psmreborn.nopsmdrm.R;
import com.psmreborn.shared.Files;
import com.psmreborn.shared.Logger;
import com.psmreborn.shared.Root;
public class LicenseCheckActivity extends Activity {
private static final int RESPONSE_CODE = 19941203;
private String entitlementId = null;
private byte[] inputData = null;
private ProgressDialog dialog = null;
public void respond(byte[] response, int resp){
Intent resIntent = new Intent();
resIntent.putExtra("result_data", response);
this.setResult(resp, resIntent);
this.dialog.dismiss();
this.finish();
}
@Override
@ -28,34 +35,48 @@ public class LicenseCheckActivity extends Activity {
}
}
private void forwardIntentToPsm() {
Log.i("TicketGen", "Forwarding intent to PSM ...");
Intent intent = new Intent("com.playstation.android.intent.action.CHECK_ENTITLEMENT");
intent.putExtra("entitlement_id", this.entitlementId);
intent.putExtra("input_data", this.inputData);
intent.setPackage(this.getResources().getString(R.string.psm_app_package_id));
startActivityForResult(intent, RESPONSE_CODE);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Read intent from pss game
this.entitlementId = this.getIntent().getStringExtra("entitlement_id");
this.inputData = this.getIntent().getByteArrayExtra("input_data");
// Read intent from ps1 game
String entitlement_id = this.getIntent().getStringExtra("entitlement_id");
byte[] input_data = this.getIntent().getByteArrayExtra("input_data");
this.dialog = new ProgressDialog(this);
this.dialog.setTitle("Generating NP Ticket ...");
this.dialog.setMessage("Faking entitlement: "+this.entitlementId);
this.dialog.setIndeterminate(true);
this.dialog.setCancelable(false);
this.dialog.show();
Logger.logText("ENTITLEMENT_ID", entitlement_id);
Logger.logBytes("INPUT_DATA", input_data);
Logger.logText("ENTITLEMENT_ID", this.entitlementId);
Logger.logBytes("INPUT_DATA", this.inputData);
// Generate ticket and put it into com.playstation.psstore databases.
Handler handler = new Handler(this.getMainLooper());
new Thread(()->{
try {
Files.cleanupFiles(this);
if(Root.init(this)){
PsmStartupCache.addEntitlement(this, entitlement_id);
PsmStartupCache.addEntitlement(this, this.entitlementId);
handler.post(() ->{
// Forward intent to psm.apk
Intent intent = new Intent("com.playstation.android.intent.action.CHECK_ENTITLEMENT");
intent.putExtra("entitlement_id", entitlement_id);
intent.putExtra("input_data", input_data);
intent.setPackage("com.playstation.psstore");
startActivityForResult(intent, RESPONSE_CODE);
this.forwardIntentToPsm();
});
}
else{

View File

@ -0,0 +1,112 @@
package com.psmreborn.nops1drm;
import android.util.Log;
import com.psmreborn.shared.Logger;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.SecureRandom;
import java.security.spec.ECGenParameterSpec;
import java.util.ArrayList;
import yuv.pink.npticket.BrokenTicketException;
import yuv.pink.npticket.Cipher;
import yuv.pink.npticket.Entitlement;
import yuv.pink.npticket.NPDate;
import yuv.pink.npticket.NPTicket;
import yuv.pink.npticket.Subject;
public class NpTicketGenerator {
private static KeyPair generateRsaKeys() throws Exception {
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(1536);
return kpg.generateKeyPair();
}
private static KeyPair generateEcKeys() throws Exception {
KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC");
kpg.initialize(new ECGenParameterSpec("secp521r1"), new SecureRandom());
return kpg.generateKeyPair();
}
public static boolean ticketExpired(byte[] ticket) {
try {
NPTicket nptik = new NPTicket();
nptik.parse(ticket, new Cipher(0x79F97BD), false);
return nptik.isExpired();
} catch (IOException e){
return true;
} catch (BrokenTicketException e) {
return true;
} catch (Exception e){
return true;
}
}
public static byte[] generateTicket(String entitlementId, String language, String onlineId, Long accountId) throws Exception {
NPTicket ticket = new NPTicket();
String serviceId = entitlementId.substring(0x0, 0x13);
Log.i("TicketGen", "Generating ticket... ("+serviceId+") ("+entitlementId+")");
// set ticket haeder
ticket.majorVersion = 4;
ticket.minorVersion = 0;
ticket.packetID = 1;
ticket.partialPacket = false;
ticket.jumboPacket = false;
// set ticket serial ..
Log.i("TicketGen", "Generating serial number...");
ticket.serial = new byte[0x14];
new SecureRandom().nextBytes(ticket.serial);
Logger.logBytes("TICKET_SERIAL", ticket.serial);
ticket.issuerID = 256;
ticket.issuedDate = System.currentTimeMillis();
ticket.notOnOrAfterDate = System.currentTimeMillis() + (1209600 * 1000);
Log.i("TicketGen", "Setting DOB...");
// set DOB
NPDate npDob = new NPDate();
npDob.year = 1999;
npDob.day = 1;
npDob.month = 1;
// set subject
Log.i("TicketGen", "Setting Subject...");
ticket.subject = new Subject(accountId, onlineId,
new byte[] { language.getBytes("UTF-8")[0], language.getBytes("UTF-8")[1], 0x00, 0x04 },
"d7", serviceId, npDob, 0x19000200, 0);
// set cookie
ticket.cookie = null;
// set entitlement
Log.i("TicketGen", "Setting Entitlements ...");
ticket.entitlements = new ArrayList<Entitlement>();
ticket.entitlements.add(new Entitlement(entitlementId, System.currentTimeMillis(), 0L, 0, 0, 0));
// set footer
Log.i("TicketGen", "Setting Footer...");
ticket.roles = null;
ticket.platform = "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000";
ticket.consoleID = new byte[0x40];
ticket.dontHaveRSASignature = false;
ByteArrayOutputStream stream = new ByteArrayOutputStream();
Log.i("TicketGen", "Writing ticket to memory stream...");
//TODO: fix ecdsa cipher, and actually generate a signature
ticket.writeTo(stream, new Cipher(0x79F97BD));
return stream.toByteArray();
}
}

View File

@ -2,14 +2,15 @@ package com.psmreborn.nops1drm;
import android.content.ContentValues;
import android.content.Context;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;
import com.psmreborn.nopsmdrm.PsmSharedPrefs;
import com.psmreborn.nopsmdrm.R;
import com.psmreborn.shared.Helper;
import com.psmreborn.shared.Logger;
import com.psmreborn.shared.Packages;
import com.psmreborn.shared.PsmApplication;
import com.psmreborn.shared.Root;
import com.psmreborn.shared.StringEncryptor;
@ -39,30 +40,30 @@ public class PsmStartupCache {
}
}
private static void copyToPsm(Context ctx) throws Exception {
String psmDataDir = Helper.getPsmAppInfo(ctx).dataDir;
String psmDataDir = PsmApplication.getPsmAppInfo(ctx).dataDir;
String psmDatabasesDir = new File(psmDataDir, "databases").getAbsolutePath();
String psmStartContentDb = new File(psmDatabasesDir, "start_content.db").getAbsolutePath();
String myDataDir = Helper.getAppInfo(ctx, ctx.getPackageName()).dataDir;
String myDataDir = Packages.getAppInfo(ctx, ctx.getPackageName()).dataDir;
String myDatabasesDir = new File(myDataDir, "databases").getAbsolutePath();
String myStartContentDb = new File(myDatabasesDir, "start_content.db").getAbsolutePath();
Root.mkdirAndChmodChown(psmDatabasesDir, 771, String.valueOf(Helper.getPsmUid(ctx)));
Root.copyChmodAndChown(myStartContentDb, psmStartContentDb, 660, String.valueOf(Helper.getPsmUid(ctx)));
Root.mkdirAndChmodChown(psmDatabasesDir, 771, String.valueOf(PsmApplication.getPsmUid(ctx)));
Root.copyChmodAndChown(myStartContentDb, psmStartContentDb, 660, String.valueOf(PsmApplication.getPsmUid(ctx)));
}
private static void copyFromPsm(Context ctx) throws Exception {
String psmDataDir = Helper.getPsmAppInfo(ctx).dataDir;
String psmDataDir = PsmApplication.getPsmAppInfo(ctx).dataDir;
String psmDatabasesDir = new File(psmDataDir, "databases").getAbsolutePath();
String psmStartContentDb = new File(psmDatabasesDir, "start_content.db").getAbsolutePath();
String myDataDir = Helper.getAppInfo(ctx, ctx.getPackageName()).dataDir;
String myDataDir = Packages.getAppInfo(ctx, ctx.getPackageName()).dataDir;
String myDatabasesDir = new File(myDataDir, "databases").getAbsolutePath();
String myStartContentDb = new File(myDatabasesDir, "start_content.db").getAbsolutePath();
Root.mkdirAndChmodChown(myDatabasesDir, 771, String.valueOf(Helper.getMyUid(ctx)));
Root.copyChmodAndChown(psmStartContentDb, myStartContentDb, 660, String.valueOf(Helper.getMyUid(ctx)));
Root.mkdirAndChmodChown(myDatabasesDir, 771, String.valueOf(Packages.getAppUid(ctx, ctx.getPackageName())));
Root.copyChmodAndChown(psmStartContentDb, myStartContentDb, 660, String.valueOf(Packages.getAppUid(ctx, ctx.getPackageName())));
}
private static int dbRemoveEntry(StartContentDb cdb, String entitlementId) {
private static int dbRemoveEntry(StartContentDbOpenHelper cdb, String entitlementId) {
Logger.logText("DELETE, ENTITLEMENT_ID", entitlementId);
SQLiteDatabase db = cdb.getWritableDatabase();
int v = db.delete("cache_table", "entitlement_id = ?", new String[]{entitlementId});
@ -70,7 +71,7 @@ public class PsmStartupCache {
return v;
}
private static byte[] dbGetEntry(StartContentDb cdb, String entitlementId){
private static byte[] dbGetEntry(StartContentDbOpenHelper cdb, String entitlementId){
Log.i("TicketGen", "dbGetEntry, "+entitlementId);
SQLiteDatabase db = cdb.getReadableDatabase();
Cursor query = db.query("cache_table", new String[] {"_id", "user_id", "entitlement_id", "ticket_data", "last_update"}, "entitlement_id = ?", new String[]{entitlementId}, null, null, null);
@ -86,7 +87,7 @@ public class PsmStartupCache {
}
}
private static void dbAddEntry(StartContentDb cdb, String userId, String entitlementId, byte[] ticket) throws Exception {
private static void dbAddEntry(StartContentDbOpenHelper cdb, String userId, String entitlementId, byte[] ticket) throws Exception {
Log.i("TicketGen", "dbAddEntry, "+entitlementId);
SQLiteDatabase db = cdb.getWritableDatabase();
@ -115,26 +116,26 @@ public class PsmStartupCache {
public static void addEntitlement(Context ctx, String entitlement_id) throws Exception {
stringEncryptor = new StringEncryptor(Helper.getAndroidIdOfPsm(ctx), Helper.getPsmUid(ctx));
stringEncryptor = new StringEncryptor(PsmApplication.getAndroidIdOfPsm(ctx), PsmApplication.getPsmUid(ctx));
try{copyFromPsm(ctx);} catch (Exception ignored) { };
// get default values for onlineid, accountid, etc.
String email = stringEncryptor.decryptString(Helper.getSharedPrefFromPsm(ctx, "SigninInfo", "SignedInUsername"), ctx.getResources().getString(R.string.default_email));
Long accountId = Long.valueOf(stringEncryptor.decryptString(Helper.getSharedPrefFromPsm(ctx, "com.playstation.psstore_preferences", "last_signin_account_id"), String.valueOf(Helper.getDefaultAccountId(ctx))));
String email = stringEncryptor.decryptString(PsmApplication.getSharedPrefFromPsm(ctx, "SigninInfo", "SignedInUsername"), ctx.getResources().getString(R.string.default_email));
Long accountId = Long.valueOf(stringEncryptor.decryptString(PsmApplication.getSharedPrefFromPsm(ctx, "com.playstation.psstore_preferences", "last_signin_account_id"), String.valueOf(PsmSharedPrefs.getDefaultAccountId(ctx))));
String onlineId = ctx.getResources().getString(R.string.default_online_id);
// read psm start content.db file ..
StartContentDb scdb = new StartContentDb(ctx);
StartContentDbOpenHelper scdb = new StartContentDbOpenHelper(ctx);
byte[] ticket = dbGetEntry(scdb, entitlement_id);
if(ticket == null){
Log.i("TicketGen", "No ticket found, generating new!");
dbAddEntry(scdb, email, entitlement_id, TicketGen.generateTicket(entitlement_id, Locale.getDefault().getLanguage(), onlineId, accountId));
dbAddEntry(scdb, email, entitlement_id, NpTicketGenerator.generateTicket(entitlement_id, Locale.getDefault().getLanguage(), onlineId, accountId));
}
else{
if(!TicketGen.ticketExpired(ticket)) {
if(NpTicketGenerator.ticketExpired(ticket)) {
Log.i("TicketGen", "Previous ticket expired, generating new one!");
dbRemoveEntry(scdb, entitlement_id);
dbAddEntry(scdb, email, entitlement_id, TicketGen.generateTicket(entitlement_id, Locale.getDefault().getLanguage(), onlineId, accountId));
dbAddEntry(scdb, email, entitlement_id, NpTicketGenerator.generateTicket(entitlement_id, Locale.getDefault().getLanguage(), onlineId, accountId));
}
else{
Log.i("TicketGen", "Existing ticket is all good! continuing to PSM!");

View File

@ -4,13 +4,13 @@ import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
final class StartContentDb extends SQLiteOpenHelper {
public StartContentDb(Context context) {
final class StartContentDbOpenHelper extends SQLiteOpenHelper {
public StartContentDbOpenHelper(Context context) {
this(context, "start_content.db");
}
private StartContentDb(Context context, String str) {
super(context, str, (SQLiteDatabase.CursorFactory) null, 1);
private StartContentDbOpenHelper(Context context, String dbName) {
super(context, dbName, (SQLiteDatabase.CursorFactory) null, 1);
}
@Override // android.database.sqlite.SQLiteOpenHelper

View File

@ -1,82 +0,0 @@
package com.psmreborn.nops1drm;
import com.psmreborn.shared.Logger;
import java.util.Arrays;
public class TicketGen {
private static final byte[] baseTicket = {(byte)0x41, (byte)0x00, (byte)0x00, (byte)0x04, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x01, (byte)0x5D, (byte)0x30, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x01, (byte)0x0F, (byte)0x00, (byte)0x08, (byte)0x00, (byte)0x14, (byte)0xBA, (byte)0x1D, (byte)0x80, (byte)0x73, (byte)0xC1, (byte)0xAE, (byte)0x02, (byte)0x75, (byte)0xD5, (byte)0xD3, (byte)0xED, (byte)0x8C, (byte)0x18, (byte)0x72, (byte)0x5A, (byte)0xA3, (byte)0x29, (byte)0x1C, (byte)0xC9, (byte)0xDF, (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x04, (byte)0x00, (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x07, (byte)0x00, (byte)0x08, (byte)0x00, (byte)0x00, (byte)0x01, (byte)0x65, (byte)0x95, (byte)0x4D, (byte)0xAC, (byte)0x7B, (byte)0x00, (byte)0x07, (byte)0x00, (byte)0x08, (byte)0x00, (byte)0x00, (byte)0x03, (byte)0xB9, (byte)0x03, (byte)0x74, (byte)0xCF, (byte)0x60, (byte)0x00, (byte)0x02, (byte)0x00, (byte)0x08, (byte)0x00, (byte)0x12, (byte)0x34, (byte)0x56, (byte)0x89, (byte)0xAB, (byte)0xCD, (byte)0xEF, (byte)0x00, (byte)0x04, (byte)0x00, (byte)0x20, (byte)0x4F, (byte)0x6E, (byte)0x6C, (byte)0x69, (byte)0x6E, (byte)0x65, (byte)0x49, (byte)0x64, (byte)0x68, (byte)0x65, (byte)0x72, (byte)0x65, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x08, (byte)0x00, (byte)0x04, (byte)0x65, (byte)0x6E, (byte)0x00, (byte)0x04, (byte)0x00, (byte)0x04, (byte)0x00, (byte)0x04, (byte)0x64, (byte)0x37, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x08, (byte)0x00, (byte)0x18, (byte)0x45, (byte)0x50, (byte)0x34, (byte)0x31, (byte)0x33, (byte)0x34, (byte)0x2D, (byte)0x4E, (byte)0x50, (byte)0x45, (byte)0x46, (byte)0x30, (byte)0x30, (byte)0x32, (byte)0x32, (byte)0x33, (byte)0x5F, (byte)0x30, (byte)0x30, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x30, (byte)0x11, (byte)0x00, (byte)0x04, (byte)0x07, (byte)0xC8, (byte)0x0C, (byte)0x06, (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x04, (byte)0x19, (byte)0x00, (byte)0x02, (byte)0x00, (byte)0x30, (byte)0x10, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x0F, (byte)0x06, (byte)0x30, (byte)0x30, (byte)0x30, (byte)0x30, (byte)0x30, (byte)0x31, (byte)0x00, (byte)0x00, (byte)0x01, (byte)0x62, (byte)0x3F, (byte)0xCE, (byte)0x27, (byte)0xD0, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x08, (byte)0x00, (byte)0x08, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x08, (byte)0x00, (byte)0x40, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x30, (byte)0x02, (byte)0x00, (byte)0x44, (byte)0x00, (byte)0x08, (byte)0x00, (byte)0x04, (byte)0xBD, (byte)0x97, (byte)0x9F, (byte)0x07, (byte)0x00, (byte)0x08, (byte)0x00, (byte)0x38, (byte)0x30, (byte)0x35, (byte)0x02, (byte)0x18, (byte)0x08, (byte)0xA4, (byte)0xC8, (byte)0xD2, (byte)0x50, (byte)0x74, (byte)0xCC, (byte)0xFA, (byte)0xF2, (byte)0xBF, (byte)0xF8, (byte)0x49, (byte)0x27, (byte)0xC3, (byte)0x04, (byte)0xA7, (byte)0x79, (byte)0xE2, (byte)0x3C, (byte)0x30, (byte)0xCA, (byte)0xE6, (byte)0x2C, (byte)0xE5, (byte)0x02, (byte)0x19, (byte)0x00, (byte)0xE0, (byte)0x4C, (byte)0x84, (byte)0x9F, (byte)0x41, (byte)0x4D, (byte)0x6B, (byte)0x0E, (byte)0xFA, (byte)0xBE, (byte)0x38, (byte)0xC4, (byte)0x72, (byte)0x2A, (byte)0x11, (byte)0x46, (byte)0x8A, (byte)0x04, (byte)0x3D, (byte)0x50, (byte)0x68, (byte)0xDC, (byte)0x99, (byte)0xA7, (byte)0x00};
private static byte[] longToBytes(long l) {
byte[] result = new byte[8];
for (int i = 8 - 1; i >= 0; i--) {
result[i] = (byte)(l & 0xFF);
l >>= Byte.SIZE;
}
return result;
}
private static long bytesToLong(final byte[] b) {
long result = 0;
for (int i = 0; i < 8; i++) {
result <<= Byte.SIZE;
result |= (b[i] & 0xFF);
}
return result;
}
private static void cpy(byte[] src, int srcOffset, byte[] dst, int dstOffset, int cpMaxLen){
for(int i = 0; i < cpMaxLen; i++){
byte b = 0;
if((i + srcOffset) < src.length) {
b = src[i + srcOffset];
}
dst[i + dstOffset] = b;
}
}
public static boolean ticketExpired(byte[] ticket){
byte[] expireDateBytes = new byte[0x8];
cpy(ticket, 0x40, expireDateBytes, 0, 0x8);
long expDate = bytesToLong(expireDateBytes);
return expDate >= System.currentTimeMillis();
}
public static byte[] generateTicket(String entitlmentId, String language, String onlineId, Long accountId) throws Exception {
Logger.logText("ENTITLEMENT_ID", entitlmentId);
Logger.logText("LANGUAGE", language);
Logger.logText("ONLINE_ID", onlineId);
Logger.logText("ACCOUNT_ID", String.valueOf(accountId));
long curTime = System.currentTimeMillis();
long expireTime = System.currentTimeMillis() + (1209600 * 1000);
Logger.logText("CUR_TIME", String.valueOf(curTime));
Logger.logText("EXPIRE_TIME", String.valueOf(expireTime));
String servicePart = entitlmentId.substring(0x0, 0x13);
String entitlementPart = entitlmentId.substring(0x14);
Logger.logText("SERVICE_PART", servicePart);
Logger.logText("ENTITLEMENT_PART", entitlementPart);
// get a copy of the base ticket ...
byte[] newTicket = Arrays.copyOf(baseTicket, baseTicket.length);
// copy strings to new ticket ..
cpy(servicePart.getBytes("UTF-8"), 0, newTicket, 0x8C, 0x18);
cpy(entitlementPart.getBytes("UTF-8"), 0, newTicket, 0xBB, 0x6);
cpy(onlineId.getBytes("UTF-8"), 0, newTicket, 0x58, 0x20);
cpy(language.getBytes("UTF-8"), 0, newTicket, 0x7C, 0x2);
// copy longs to ticket
cpy(longToBytes(accountId), 0, newTicket, 0x4C, 0x8);
cpy(longToBytes(curTime), 0, newTicket, 0x34, 0x8);
cpy(longToBytes(expireTime), 0, newTicket, 0x40, 0x8);
// return the patched ticket.
return newTicket;
}
}

View File

@ -1,6 +1,7 @@
package com.psmreborn.nopsmdrm;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
@ -10,12 +11,20 @@ import android.os.Environment;
import android.os.Handler;
import android.util.Log;
import com.psmreborn.shared.Helper;
import com.psmreborn.shared.PsmApplication;
import java.io.File;
import java.io.IOException;
public class DumpAllRifs {
private static void showErrorMessage(Activity ctx, String errorMsg){
new AlertDialog.Builder(ctx)
.setTitle("Error Occurred.")
.setMessage(errorMsg)
.setCancelable(false)
.setPositiveButton("Ok",null).show();
}
public static void setDumpAllFlagAndStartPsm(Activity ctx) {
ProgressDialog dialog = new ProgressDialog(ctx);
dialog.setTitle("Starting PSM ...");
@ -28,14 +37,26 @@ public class DumpAllRifs {
Handler handler = new Handler(ctx.getMainLooper());
File psmFolder = new File(Environment.getExternalStorageDirectory(), "psm");
File psmDumpAllFlagFile = new File(psmFolder, "dump_all");
File psmAndroidFolder = new File(new File(new File(new File(new File(Environment.getExternalStorageDirectory(), "Android"), "data"), "com.playstation.psstore"), "files"), "psm");
File psmAndroidFolder = new File(new File(new File(new File(new File(Environment.getExternalStorageDirectory(), "Android"), "data"), ctx.getResources().getString(R.string.psm_app_package_id)), "files"), "psm");
// stop psm
Helper.killPsm(ctx);
PsmApplication.killPsm(ctx);
if(!psmAndroidFolder.exists()){
handler.post(() -> {
dialog.dismiss();
showErrorMessage(ctx, psmAndroidFolder.getAbsolutePath()+" does not exist (do you have no games?)");
});
return;
}
try {
psmDumpAllFlagFile.createNewFile();
} catch (IOException e) {
handler.post(() -> {
dialog.dismiss();
showErrorMessage(ctx, e.toString());
});
return;
}
@ -49,7 +70,11 @@ public class DumpAllRifs {
}
}
if(titleId.equals("")){
if(titleId.isEmpty()) {
handler.post(() -> {
dialog.dismiss();
showErrorMessage(ctx, "No title id could be found.");
});
return;
}
@ -72,6 +97,11 @@ public class DumpAllRifs {
});
}
else{
handler.post(() -> {
dialog.dismiss();
showErrorMessage(ctx, "WifiManager was null");
});
return;
}
}).start();

View File

@ -6,7 +6,7 @@ import android.app.ProgressDialog;
import android.os.Environment;
import android.os.Handler;
import com.psmreborn.shared.Helper;
import com.psmreborn.shared.PsmApplication;
import com.psmreborn.shared.Root;
import java.io.File;
@ -23,12 +23,12 @@ public class FixPermissions {
new Thread(() -> {
Handler handler = new Handler(ctx.getMainLooper());
Helper.killPsm(ctx);
PsmApplication.killPsm(ctx);
String androidDataFolder = new File(new File(Environment.getExternalStorageDirectory(), "Android"), "data").getAbsolutePath();
try {
String groupId = Root.getFileGroup(androidDataFolder);
String userId = String.valueOf(Helper.getPsmAppInfo(ctx).uid);
Root.chownRoot(new File(new File(new File(androidDataFolder, "com.playstation.psstore"), "files"), "psm").getAbsolutePath(), userId, groupId);
String userId = String.valueOf(PsmApplication.getPsmAppInfo(ctx).uid);
Root.chownRoot(new File(new File(new File(androidDataFolder, ctx.getResources().getString(R.string.psm_app_package_id)), "files"), "psm").getAbsolutePath(), userId, groupId);
handler.post(() -> {
dialog.dismiss();

View File

@ -4,27 +4,26 @@ package com.psmreborn.nopsmdrm;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import com.psmreborn.pscertified.PlayStationCertified;
import com.psmreborn.pscertified.PsCertificatesInstaller;
import com.psmreborn.shared.Downloader;
import com.psmreborn.shared.Helper;
import com.psmreborn.shared.PsmApplication;
import com.psmreborn.shared.Root;
import java.io.File;
public class MainActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
(new Startup(this)).execute();
Startup.runStartupCheck(this);
}
@Override
@ -35,7 +34,7 @@ public class MainActivity extends Activity {
}
private void downloadPsmAlert() {
new AlertDialog.Builder((Activity)this)
new AlertDialog.Builder(this)
.setTitle("PSM App not found!")
.setMessage("Would you like to download and install the PlayStation Mobile app?")
.setCancelable(false)
@ -49,16 +48,16 @@ public class MainActivity extends Activity {
.setNegativeButton("No", null).show();
}
private void psCertifiedAlert(){
private void psCertifiedAlert() {
new AlertDialog.Builder(this)
.setTitle("PS Certification Missing")
.setMessage((Build.VERSION.SDK_INT >= 23) ? "Your device appears to not be \"PlayStation Certified\"\nOn android 6+ this requires installing a Magisk module\nWould you like to install \"MagiskCertify.zip\"" :
.setMessage((Root.isMagiskRoot()) ? "Your device appears to not be \"PlayStation Certified\"\nOn android 6+ this requires installing a Magisk module\nWould you like to install \"MagiskCertify.zip\"" :
"Your device appears to not be \"PlayStation Certified\"\nDo you want to install them?\n(Warning: modifies /system/)")
.setCancelable(false)
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
(new PsCertificatesInstaller(MainActivity.this)).execute();
PsCertificatesInstaller.installPsCertificates(MainActivity.this);
}
})
.setNegativeButton("No", null).show();
@ -70,11 +69,11 @@ public class MainActivity extends Activity {
if(!PlayStationCertified.isPlaystationCertified(this.getApplicationContext())){
psCertifiedAlert();
}
else if(!Helper.isPsmInstalled(this)) {
else if(!PsmApplication.isPsmInstalled(this)) {
downloadPsmAlert();
}
else {
new NoPsmDrmInstaller(this).execute();
NoPsmDrmInstaller.installNoPsmDrm(this);
}
}
}

View File

@ -1,8 +1,5 @@
package com.psmreborn.nopsmdrm;
import static com.psmreborn.shared.Helper.*;
import static com.psmreborn.shared.Root.*;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
@ -10,47 +7,39 @@ import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.pm.PackageManager;
import android.os.AsyncTask;
import android.database.sqlite.SQLiteDatabase;
import android.os.Build;
import android.os.Environment;
import android.os.Handler;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.widget.Toast;
import com.psmreborn.nopsmdrm.library_db.LibraryDbOpenHelper;
import com.psmreborn.shared.Files;
import com.psmreborn.shared.Helper;
import com.psmreborn.shared.MountPoint;
import com.psmreborn.shared.Packages;
import com.psmreborn.shared.PsmApplication;
import com.psmreborn.shared.Root;
import com.psmreborn.shared.StringEncryptor;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.RandomAccessFile;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Locale;
import java.util.Date;
import eu.chainfire.libsuperuser.Shell;
// Sorry if this is kinda hard to follow ...
public class NoPsmDrmInstaller extends AsyncTask<Void, Void, Void> {
private boolean wasError = false;
private String errorMsg = "";
private ProgressDialog dialog = null;
public class NoPsmDrmInstaller{
private Context ctx = null;
private Handler handler = null;
public NoPsmDrmInstaller(Context context){
this.ctx = context;
this.handler = new Handler(ctx.getMainLooper());
private NoPsmDrmInstaller(Context context) {
ctx = context;
handler = new Handler(ctx.getMainLooper());
}
private void setError(String msg) throws Exception {
this.wasError = true;
this.errorMsg = msg;
Log.e("INSTALLER",errorMsg);
throw new Exception(msg);
}
@SuppressLint("MissingPermission")
private void generateDeviceFingerprint(String outputFilename) throws Exception {
@ -92,8 +81,8 @@ public class NoPsmDrmInstaller extends AsyncTask<Void, Void, Void> {
type = "(blank)";
PrintWriter writer = new PrintWriter(outputFilename, "UTF-8");
writer.println(String.valueOf(Helper.getPsmUid(ctx)));
writer.println(Helper.getAndroidIdOfPsm(ctx));
writer.println(String.valueOf(PsmApplication.getPsmUid(ctx)));
writer.println(PsmApplication.getAndroidIdOfPsm(ctx));
writer.println(deviceId);
writer.println(serial);
writer.println(brand);
@ -106,16 +95,16 @@ public class NoPsmDrmInstaller extends AsyncTask<Void, Void, Void> {
}
@SuppressLint("SimpleDateFormat")
private void backupPsm() throws Exception {
String psmFilesDir = new File(Helper.getPsmAppInfo(ctx).dataDir, "files").getAbsolutePath();
String psmFilesDir = new File(PsmApplication.getPsmAppInfo(ctx).dataDir, "files").getAbsolutePath();
String psmKdcDir = new File(psmFilesDir, "kdc").getAbsolutePath();
String psmActFile = new File(psmKdcDir, "act.dat").getAbsolutePath();
String psmAndroidFolder = new File(new File(new File(new File(new File(Environment.getExternalStorageDirectory(), "Android"), "data"), "com.playstation.psstore"), "files"), "psm").getAbsolutePath();
String psmAndroidFolder = new File(new File(new File(new File(new File(Environment.getExternalStorageDirectory(), "Android"), "data"), ctx.getResources().getString(R.string.psm_app_package_id)), "files"), "psm").getAbsolutePath();
String psmSdcardFolder = new File(Environment.getExternalStorageDirectory(), "psm").getAbsolutePath();
String devinfoFile = new File(ctx.getCacheDir(), "devinfo.txt").getAbsolutePath();
String tarFilename = new File(psmSdcardFolder, "psm_"+getDateTime() + ".tar").getAbsolutePath();
String tarFilename = new File(psmSdcardFolder, "psm_"+ new SimpleDateFormat("MM_dd_yyyy_HH_mm_ss").format(new Date()) + ".tar").getAbsolutePath();
// check if "act.dat" exists -- they've used PSM before ...
@ -127,7 +116,7 @@ public class NoPsmDrmInstaller extends AsyncTask<Void, Void, Void> {
generateDeviceFingerprint(devinfoFile);
ArrayList<String> filesToTar = new ArrayList<String>();
filesToTar.add(Helper.getPsmAppInfo(ctx).dataDir);
filesToTar.add(PsmApplication.getPsmAppInfo(ctx).dataDir);
filesToTar.add(devinfoFile);
// add all license folders ....
@ -141,7 +130,7 @@ public class NoPsmDrmInstaller extends AsyncTask<Void, Void, Void> {
}
// tar up the files
tarRoot(filesToTar, tarFilename);
Root.tarRoot(filesToTar, tarFilename);
handler.post(() -> {
Toast.makeText(ctx.getApplicationContext(),"Backed up existing PSM Data to:\n\""+tarFilename+"\"", Toast.LENGTH_LONG).show();
@ -150,132 +139,51 @@ public class NoPsmDrmInstaller extends AsyncTask<Void, Void, Void> {
}
private void makeDirs() throws PackageManager.NameNotFoundException, Shell.ShellDiedException {
mkdirAndChmodChown(new File(Helper.getPsmAppInfo(ctx).dataDir, "cache").getAbsolutePath(), 771, String.valueOf(Helper.getPsmUid(ctx)));
mkdirAndChmodChown(new File(Helper.getPsmAppInfo(ctx).dataDir, "shared_prefs").getAbsolutePath(), 771, String.valueOf(Helper.getPsmUid(ctx)));
mkdirAndChmodChown(new File(Helper.getPsmAppInfo(ctx).dataDir, "files").getAbsolutePath(), 771, String.valueOf(Helper.getPsmUid(ctx)));
mkdirAndChmodChown(new File(new File(Helper.getPsmAppInfo(ctx).dataDir, "files"), "kdc").getAbsolutePath(), 771, String.valueOf(Helper.getPsmUid(ctx)));
mkdirAndChmodChown(new File(Helper.getPsmAppInfo(ctx).dataDir, "databases").getAbsolutePath(), 771, String.valueOf(Helper.getPsmUid(ctx)));
Root.mkdirAndChmodChown(new File(PsmApplication.getPsmAppInfo(ctx).dataDir, "cache").getAbsolutePath(), 771, String.valueOf(PsmApplication.getPsmUid(ctx)));
Root.mkdirAndChmodChown(new File(PsmApplication.getPsmAppInfo(ctx).dataDir, "shared_prefs").getAbsolutePath(), 771, String.valueOf(PsmApplication.getPsmUid(ctx)));
Root.mkdirAndChmodChown(new File(PsmApplication.getPsmAppInfo(ctx).dataDir, "files").getAbsolutePath(), 771, String.valueOf(PsmApplication.getPsmUid(ctx)));
Root.mkdirAndChmodChown(new File(new File(PsmApplication.getPsmAppInfo(ctx).dataDir, "files"), "kdc").getAbsolutePath(), 771, String.valueOf(PsmApplication.getPsmUid(ctx)));
Root.mkdirAndChmodChown(new File(PsmApplication.getPsmAppInfo(ctx).dataDir, "databases").getAbsolutePath(), 771, String.valueOf(PsmApplication.getPsmUid(ctx)));
}
private void generateWorkaroundSharedPrefs(String sharedPrefsPath, String androidId, int psmUid) throws Exception {
StringEncryptor stringEncryptor = new StringEncryptor(androidId, psmUid);
String emailAddress = stringEncryptor.encryptString("nopsmdrm@transrights.lgbt");
String password = stringEncryptor.encryptString("password");
// get the cache folder for our 'shared_prefs'
private void installSharedPref(String sharedPrefData, String sharedPrefName) throws Exception {
String sharedPrefsPath = new File(PsmApplication.getPsmAppInfo(ctx).dataDir, "shared_prefs").getAbsolutePath();
String tmpPrefsFolder = ctx.getCacheDir().getAbsolutePath();
String myPrefFile = new File(tmpPrefsFolder, sharedPrefName).getAbsolutePath();
String psmPrefFile = new File(sharedPrefsPath, sharedPrefName).getAbsolutePath();
String aidSigninInfo = new File(tmpPrefsFolder, "AIDSigninInfo.xml").getAbsolutePath();
String signinInfo = new File(sharedPrefsPath, "SigninInfo.xml").getAbsolutePath();
// generate shared_prefs
Files.writeTxtFile(aidSigninInfo, "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n" +
"<map>\n<string name=\"SignedInUsername\">"+emailAddress+"</string>\n" +
"<boolean name=\"PassSave\" value=\"true\" />\n" +
"<string name=\"Password\">"+password+"</string>\n" +
"<boolean name=\"AutoSignIn\" value=\"true\" />\n" +
"</map>\n");
copyChmodAndChown(aidSigninInfo, signinInfo, 660, String.valueOf(Helper.getPsmUid(ctx)));
}
private void generateSharedPrefs(String sharedPrefsPath, String androidId, int psmUid) throws Exception {
StringEncryptor stringEncryptor = new StringEncryptor(androidId, psmUid);
// encrypt the actual strings, username, password, etc
String emailAddress = stringEncryptor.encryptString(ctx.getResources().getString(R.string.default_email));
String password = stringEncryptor.encryptString(ctx.getResources().getString(R.string.default_password));
String accountId = stringEncryptor.encryptString(String.valueOf(Long.valueOf(ctx.getResources().getString(R.string.default_account_id), 16)));
// get the cache folder for our 'shared_prefs'
String tmpPrefsFolder = ctx.getCacheDir().getAbsolutePath();
// work out paths to each file ...
String c_signinInfo = new File(tmpPrefsFolder, "SigninInfo.xml").getAbsolutePath();
String c_psstorePrefs = new File(tmpPrefsFolder, "com.playstation.psstore_preferences.xml").getAbsolutePath();
String c_runningContentInfo = new File(tmpPrefsFolder, "RunningContentInfo.xml").getAbsolutePath();
String c_localLibrary = new File(tmpPrefsFolder, "LocalLibrary.xml").getAbsolutePath();
String r_signinInfo = new File(sharedPrefsPath, "SigninInfo.xml").getAbsolutePath();
String r_psstorePrefs = new File(sharedPrefsPath, "com.playstation.psstore_preferences.xml").getAbsolutePath();
String r_runningContentInfo = new File(sharedPrefsPath, "RunningContentInfo.xml").getAbsolutePath();
String r_localLibrary = new File(sharedPrefsPath, "LocalLibrary.xml").getAbsolutePath();
// generate shared_prefs
Files.writeTxtFile(c_signinInfo, "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n" +
"<map>\n<string name=\"SignedInUsername\">"+emailAddress+"</string>\n" +
"<boolean name=\"PassSave\" value=\"true\" />\n" +
"<string name=\"Password\">"+password+"</string>\n" +
"<boolean name=\"AutoSignIn\" value=\"true\" />\n" +
"</map>\n");
Files.writeTxtFile(c_psstorePrefs, "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n" +
"<map>\n" +
"<boolean name=\"key_upgradeDownloadTableForNeedWifi\" value=\"true\" />\n" +
"<string name=\"last_signin_account_id\">"+accountId+"</string>\n" +
"<long name=\"last_signin_account_region\" value=\"2\" />\n" +
"<int name=\"key_psstore\" value=\"1\" />\n" +
"<int name=\"key_downloader\" value=\"1\" />\n" +
"<int name=\"psm_license_agree_version_code\" value=\"1170\" />\n" +
"<int name=\"key_xmlcache\" value=\"1\" />\n" +
"<string name=\"last_signin_account_country\">US</string>\n" +
"<int name=\"key_startcontent\" value=\"1\" />\n<int name=\"key_nsxevent\" value=\"1\" />\n" +
"<boolean name=\"key_upgradeLibraryTableForLocationUseConfirmationDate\" value=\"true\" />\n" +
"<int name=\"key_install\" value=\"1\" />\n" +
"<string name=\"update_md5\">387ce7e424258aef426aaa5be8a1638a</string>\n" +
"<boolean name=\"psm_license_agree\" value=\"true\" />\n" +
"<int name=\"key_guestinfo\" value=\"1\" />\n" +
"<string name=\"last_signin_account_language\">"+ Locale.getDefault().getLanguage()+"</string>\n" +
"<int name=\"key_cache\" value=\"2\" />\n" +
"<int name=\"key_signinfo\" value=\"2\" />\n" +
"</map>\n");
Files.writeTxtFile(c_runningContentInfo, "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n" +
"<map>\n<null name=\"title_id\" />\n" +
"<null name=\"next_title_id\" />\n" +
"</map>\n");
Files.writeTxtFile(c_localLibrary, "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n" +
"<map>\n<boolean name=\"notDisplayAgain\" value=\"true\" />\n" +
"<int name=\"sortType\" value=\"0\" />\n" +
"<boolean name=\"isList\" value=\"false\" />\n" +
"</map>\n");
// copy to the correct place and set permissions properly.
copyChmodAndChown(c_signinInfo, r_signinInfo, 660, String.valueOf(Helper.getPsmUid(ctx)));
copyChmodAndChown(c_psstorePrefs, r_psstorePrefs, 660, String.valueOf(Helper.getPsmUid(ctx)));
copyChmodAndChown(c_runningContentInfo, r_runningContentInfo, 660, String.valueOf(Helper.getPsmUid(ctx)));
copyChmodAndChown(c_localLibrary, r_localLibrary, 660, String.valueOf(Helper.getPsmUid(ctx)));
}
private boolean isNoPsmDrmAccountId(String androidId, int psmUid) throws Exception {
StringEncryptor stringEncryptor = new StringEncryptor(androidId, psmUid);
long accountId = Long.parseLong(stringEncryptor.decryptString(Helper.getSharedPrefFromPsm(ctx, "com.playstation.psstore_preferences", "last_signin_account_id"), null));
return accountId == getDefaultAccountId(ctx);
Files.writeTxtFile(myPrefFile, sharedPrefData);
Root.copyChmodAndChown(myPrefFile, psmPrefFile, 660, String.valueOf(PsmApplication.getPsmUid(ctx)));
}
private void installSharedPrefs() throws Exception {
// get the path to the shared_prefs folder
String sharedPrefsPath = new File(Helper.getPsmAppInfo(ctx).dataDir, "shared_prefs").getAbsolutePath();
String tmpPrefsFolder = ctx.getCacheDir().getAbsolutePath();
String sharedPrefsPath = new File(PsmApplication.getPsmAppInfo(ctx).dataDir, "shared_prefs").getAbsolutePath();
String androidId = Helper.getAndroidIdOfPsm(ctx);
int psmUid = Helper.getPsmUid(ctx);
// setup StringEncryptor
String androidId = PsmApplication.getAndroidIdOfPsm(ctx);
PsmSharedPrefs sharedPrefGenerator = new PsmSharedPrefs((androidId == null) ? ctx.getResources().getString(R.string.default_account_id) : androidId, PsmApplication.getPsmUid(ctx));
// check if signininfo.xml file exists or not ...
boolean signinInfoExist = fileExistRoot(new File(sharedPrefsPath, "SigninInfo.xml").getAbsolutePath());
boolean isNoPsmDrmAccount = signinInfoExist && isNoPsmDrmAccountId(androidId, psmUid);
boolean signinInfoExist = Root.fileExistRoot(new File(sharedPrefsPath, "SigninInfo.xml").getAbsolutePath());
boolean isNoPsmDrmAccount = signinInfoExist && sharedPrefGenerator.checkEncryptedAccountIdEquals(PsmApplication.getSharedPrefFromPsm(ctx, "com.playstation.psstore_preferences", "last_signin_account_id"), PsmSharedPrefs.getDefaultAccountId(ctx));
if (!signinInfoExist || isNoPsmDrmAccount) {
// if no SigninInfo.xml file was not found
// or if it was found, but it is using the default account id ...
// then generate our own shared_prefs
if(androidId != null){
generateSharedPrefs(sharedPrefsPath, androidId, psmUid);
installSharedPref(sharedPrefGenerator.generateSigninInfo(ctx.getResources().getString(R.string.default_email), ctx.getResources().getString(R.string.default_password)), "SigninInfo.xml");
installSharedPref(sharedPrefGenerator.generatePsmPreferences(PsmSharedPrefs.getDefaultAccountId(ctx)), "com.playstation.psstore_preferences.xml");
installSharedPref(sharedPrefGenerator.generateRunningContentInfo(), "RunningContentInfo.xml");
installSharedPref(sharedPrefGenerator.generateLocalLibrary(), "LocalLibrary.xml");
}
else {
generateWorkaroundSharedPrefs(sharedPrefsPath, "1234567890abcdef", psmUid);
Helper.killPsm(ctx);
installSharedPref(sharedPrefGenerator.generateSigninInfo(ctx.getResources().getString(R.string.default_email), ctx.getResources().getString(R.string.default_password)), "SigninInfo.xml");
PsmApplication.killPsm(ctx);
handler.post(() ->{
new AlertDialog.Builder((Activity)ctx)
.setTitle("Android 8+ android_id...")
@ -314,31 +222,28 @@ public class NoPsmDrmInstaller extends AsyncTask<Void, Void, Void> {
}
private void installNoPsmDrmModules() throws Exception {
String nativeLibsFolder = getPsmAppInfo(ctx).nativeLibraryDir;
String nativeLibsFolder = PsmApplication.getPsmAppInfo(ctx).nativeLibraryDir;
String libPsmKdcFile = new File(nativeLibsFolder, "libpsmkdc_jni.so").getAbsolutePath();
String libDefaultFile = new File(nativeLibsFolder, "libdefault.so").getAbsolutePath();
String realLibDefaultFile = new File(nativeLibsFolder, "libdefault_real.so").getAbsolutePath();
String folderContainingLibs = new File(nativeLibsFolder).getParentFile().getAbsolutePath();
// Check if the app is installed to the SD card or not.
boolean installedToSd = !nativeLibsFolder.startsWith("/data");
// This is the case when the app is installed to the SD Card, or /system/
boolean needRemount = MountPoint.getMountPointAt(nativeLibsFolder).isRo();
// get the owner of the file ..
String systemUid = getFileOwner(libPsmKdcFile);
String systemUid = MountPoint.getMountPointAt(nativeLibsFolder).isFat() ? null : Root.getFileOwner(libPsmKdcFile); // /mnt/sec is FAT, and doesnt support unix permissions.
if(needRemount) Root.remountRw(nativeLibsFolder); // the /mnt/asec folder is read only normally, so make ir read/write
if(installedToSd) systemUid = null; // /mnt/sec is FAT32, and doesnt support unix permissions.
if(installedToSd) remountRw(folderContainingLibs); // the /mnt/asec folder is read only normally, so make ir read/write
if(!fileExistRoot(realLibDefaultFile)) {
if(!Root.fileExistRoot(realLibDefaultFile)) {
// if libdefault_real.so not found, then rename libdefault.so to libdefault_real.so ...
moveFileRoot(libDefaultFile, realLibDefaultFile);
Root.moveFileRoot(libDefaultFile, realLibDefaultFile);
// if were on android 5.x or later, we need to patch libdefault.
if(Build.VERSION.SDK_INT >= 21){
String cachedLibDefault = new File(ctx.getCacheDir(), "libdefault_real.so").toString();
Root.copyChmodAndChown(realLibDefaultFile, cachedLibDefault, 777, String.valueOf(Helper.getMyUid(ctx)));
Root.copyChmodAndChown(realLibDefaultFile, cachedLibDefault, 777, String.valueOf(Packages.getAppUid(ctx, ctx.getPackageName())));
patchLibdefault(cachedLibDefault);
Root.copyChmodAndChown(cachedLibDefault, realLibDefaultFile, 755, systemUid);
}
@ -346,98 +251,107 @@ public class NoPsmDrmInstaller extends AsyncTask<Void, Void, Void> {
}
// unpack the library files ...
unpackResourceToLocationRoot(ctx, R.raw.libdefault, libDefaultFile, 755, systemUid);
unpackResourceToLocationRoot(ctx, R.raw.libpsmkdc_jni, libPsmKdcFile, 755, systemUid);
if(installedToSd) remountRo(folderContainingLibs);
Root.unpackResourceToLocationRoot(ctx, R.raw.libdefault, libDefaultFile, 755, systemUid);
Root.unpackResourceToLocationRoot(ctx, R.raw.libpsmkdc_jni, libPsmKdcFile, 755, systemUid);
if(needRemount) Root.remountRo(nativeLibsFolder);
}
private void installDatabase() throws Exception {
String databasesFolder = new File(getPsmAppInfo(ctx).dataDir, "databases").getAbsolutePath();
String libraryDbFile = new File(databasesFolder, "library.db").getAbsolutePath();
String psmDatabasesFolder = new File(PsmApplication.getPsmAppInfo(ctx).dataDir, "databases").getAbsolutePath();
String psmLibraryDbFile = new File(psmDatabasesFolder, "library.db").getAbsolutePath();
unpackResourceToLocationRoot(ctx, R.raw.library, libraryDbFile, 660, String.valueOf(Helper.getPsmUid(ctx)));
String myDatabasesFolder = new File(Packages.getAppInfo(ctx, ctx.getPackageName()).dataDir, "databases").getAbsolutePath();
String myLibraryDbFile = new File(myDatabasesFolder, "library.db").getAbsolutePath();
Root.mkdirAndChmodChown(myDatabasesFolder, 771, String.valueOf(Packages.getAppUid(ctx, ctx.getPackageName())));
if(Root.fileExistRoot(psmLibraryDbFile))
Root.copyChmodAndChown(psmLibraryDbFile, myLibraryDbFile, 660, String.valueOf(Packages.getAppUid(ctx, ctx.getPackageName())));
// got psm library db file
LibraryDbOpenHelper lbdb = new LibraryDbOpenHelper(ctx);
SQLiteDatabase db = lbdb.getWritableDatabase();
// add sql trigger to bypass content_id.
db.execSQL("CREATE TRIGGER IF NOT EXISTS CONTENT_ID_MEMES AFTER INSERT ON LibraryTable BEGIN UPDATE LibraryTable SET content_id=\"UM0105-\" || title_id || \"_00-0000000000000000\" WHERE title_id = new.title_id; END;");
// close sql db
db.close();
lbdb.close();
if(Root.fileExistRoot(myLibraryDbFile))
Root.copyChmodAndChown(myLibraryDbFile, psmLibraryDbFile, 660, String.valueOf(PsmApplication.getPsmUid(ctx)));
}
private void installDeviceList() throws PackageManager.NameNotFoundException, IOException, Shell.ShellDiedException {
String cacheFolder = new File(getPsmAppInfo(ctx).dataDir, "cache").getAbsolutePath();
String cacheFolder = new File(PsmApplication.getPsmAppInfo(ctx).dataDir, "cache").getAbsolutePath();
// extract the regular device list ...
String deviceList2File = new File(cacheFolder, "deviceList2.dat").getAbsolutePath();
unpackResourceToLocationRoot(ctx, R.raw.device_list2, deviceList2File, 660, String.valueOf(Helper.getPsmUid(ctx)));
Root.unpackResourceToLocationRoot(ctx, R.raw.device_list2, deviceList2File, 660, String.valueOf(PsmApplication.getPsmUid(ctx)));
// extract the additional certified devices list ...
String additionalCertsFile = new File(cacheFolder, "addtionalCertifiedDevList.dat").getAbsolutePath();
unpackResourceToLocationRoot(ctx, R.raw.aditional_certified_devices_list, additionalCertsFile, 660, String.valueOf(Helper.getPsmUid(ctx)));
Root.unpackResourceToLocationRoot(ctx, R.raw.aditional_certified_devices_list, additionalCertsFile, 660, String.valueOf(PsmApplication.getPsmUid(ctx)));
}
@Override
protected void onPreExecute() {
dialog = new ProgressDialog(ctx);
if(!Helper.isNoPsmDrmAlreadyInstalled(ctx))
public static boolean isNoPsmDrmInstalled(Context ctx) {
try {
if(new File(PsmApplication.getPsmAppInfo(ctx).nativeLibraryDir, "libdefault_real.so").exists()){
return true;
}
} catch (PackageManager.NameNotFoundException e) {
return false;
}
return false;
}
public static void installNoPsmDrm(Activity activity) {
ProgressDialog dialog = new ProgressDialog(activity);
if(!isNoPsmDrmInstalled(activity))
dialog.setTitle("Installing NoPsmDrm ...");
else
dialog.setTitle("Updating NoPsmDrm ...");
dialog.setTitle("Reinstalling NoPsmDrm ...");
dialog.setMessage("Please Wait ...");
dialog.setIndeterminate(true);
dialog.setCancelable(false);
dialog.show();
NoPsmDrmInstaller drmInstaller = new NoPsmDrmInstaller(activity.getApplicationContext());
new Thread(() -> {
try {
Files.cleanupFiles(activity);
PsmApplication.killPsm(activity);
}
drmInstaller.backupPsm();
drmInstaller.makeDirs();
drmInstaller.installSharedPrefs();
drmInstaller.installDeviceList();
drmInstaller.installNoPsmDrmModules();
drmInstaller.installDatabase();
@Override
protected Void doInBackground(Void... voids) {
try {
Helper.killPsm(ctx);
if (isPsmInstalled(ctx)) {
backupPsm();
makeDirs();
installSharedPrefs();
installDeviceList();
installNoPsmDrmModules();
installDatabase();
}
else{
this.setError("PSM app is not installed.");
catch(Exception e){
dialog.dismiss();
drmInstaller.handler.post(() -> {
new AlertDialog.Builder(activity)
.setTitle("Error Occurred.")
.setMessage(e.toString())
.setCancelable(false)
.setPositiveButton("Ok",null).show();
});
}
}
catch(Exception e){
this.wasError = true;
this.errorMsg = e.toString();
return null;
}
return null;
}
@Override
protected void onPostExecute(Void result) {
handler.post(() -> {
dialog.dismiss();
});
if(wasError) {
new AlertDialog.Builder((Activity)ctx)
.setTitle("Error Occurred.")
.setMessage(this.errorMsg)
.setCancelable(false)
.setPositiveButton("Ok",null).show();
}
else{
handler.post(() ->{
Startup.setPsmInstalled((Activity)ctx);
drmInstaller.handler.post(() -> {
dialog.dismiss();
Startup.setPsmInstalled(activity);
new AlertDialog.Builder(activity)
.setTitle("Finished!")
.setMessage("Your PSM Application was patched successfully!\n\nNote: WI-FI has to be turned off for games to work.")
.setCancelable(false)
.setPositiveButton("Ok", null).show();
});
new AlertDialog.Builder((Activity)ctx)
.setTitle("Finished!")
.setMessage("Your PSM Application was patched successfully!\n\nNote: WI-FI has to be turned off for games to work.")
.setCancelable(false)
.setPositiveButton("Ok", null).show();
}
}).start();
}
}

View File

@ -0,0 +1,69 @@
package com.psmreborn.nopsmdrm;
import android.content.Context;
import com.psmreborn.shared.StringEncryptor;
import java.util.Locale;
public class PsmSharedPrefs {
private StringEncryptor encryptor = null;
public PsmSharedPrefs(StringEncryptor stringEncryptor){
this.encryptor = stringEncryptor;
}
public PsmSharedPrefs(String androidId, int psmUid) {
this.encryptor = new StringEncryptor(androidId, psmUid);
}
public String generatePsmPreferences(Long accountId) {
return "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n" +
"<map>\n" +
"<boolean name=\"key_upgradeDownloadTableForNeedWifi\" value=\"true\" />\n" +
"<string name=\"last_signin_account_id\">"+encryptor.encryptString(String.valueOf(accountId))+"</string>\n" +
"<long name=\"last_signin_account_region\" value=\"2\" />\n" +
"<int name=\"key_psstore\" value=\"1\" />\n" +
"<int name=\"key_downloader\" value=\"1\" />\n" +
"<int name=\"psm_license_agree_version_code\" value=\"1170\" />\n" +
"<int name=\"key_xmlcache\" value=\"1\" />\n" +
"<string name=\"last_signin_account_country\">US</string>\n" +
"<int name=\"key_startcontent\" value=\"1\" />\n<int name=\"key_nsxevent\" value=\"1\" />\n" +
"<boolean name=\"key_upgradeLibraryTableForLocationUseConfirmationDate\" value=\"true\" />\n" +
"<int name=\"key_install\" value=\"1\" />\n" +
"<string name=\"update_md5\">387ce7e424258aef426aaa5be8a1638a</string>\n" +
"<boolean name=\"psm_license_agree\" value=\"true\" />\n" +
"<int name=\"key_guestinfo\" value=\"1\" />\n" +
"<string name=\"last_signin_account_language\">"+ Locale.getDefault().getLanguage()+"</string>\n" +
"<int name=\"key_cache\" value=\"2\" />\n" +
"<int name=\"key_signinfo\" value=\"2\" />\n" +
"</map>\n";
}
public String generateSigninInfo(String emailAddress, String password) {
return "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n" +
"<map>\n<string name=\"SignedInUsername\">"+encryptor.encryptString(emailAddress)+"</string>\n" +
"<boolean name=\"PassSave\" value=\"true\" />\n" +
"<string name=\"Password\">"+encryptor.encryptString(password)+"</string>\n" +
"<boolean name=\"AutoSignIn\" value=\"true\" />\n" +
"</map>\n";
}
public String generateRunningContentInfo() {
return "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n" +
"<map>\n<null name=\"title_id\" />\n" +
"<null name=\"next_title_id\" />\n" +
"</map>\n";
}
public String generateLocalLibrary() {
return "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n" +
"<map>\n<boolean name=\"notDisplayAgain\" value=\"true\" />\n" +
"<int name=\"sortType\" value=\"0\" />\n" +
"<boolean name=\"isList\" value=\"false\" />\n" +
"</map>\n";
}
public boolean checkEncryptedAccountIdEquals(String encryptedAccountId, Long checkAccountId) throws Exception {
return ( Long.parseLong(encryptor.decryptString(encryptedAccountId, String.valueOf(checkAccountId))) == checkAccountId );
}
public static long getDefaultAccountId(Context ctx){
return Long.valueOf(ctx.getResources().getString(R.string.default_account_id), 16);
}
}

View File

@ -1,7 +1,6 @@
package com.psmreborn.nopsmdrm;
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Environment;
import android.os.Handler;
@ -9,15 +8,11 @@ import android.widget.Button;
import android.widget.TextView;
import com.psmreborn.pscertified.PlayStationCertified;
import com.psmreborn.shared.Helper;
import com.psmreborn.shared.Files;
import com.psmreborn.shared.PsmApplication;
import com.psmreborn.shared.Root;
import eu.chainfire.libsuperuser.Shell;
public class Startup extends AsyncTask<Void, Void, Void> {
private Activity ctx = null;
private Handler handler = null;
private boolean wasError = false;
private String errorMsg = "";
public class Startup {
public static void updateNames(Activity activity) {
@ -25,10 +20,10 @@ public class Startup extends AsyncTask<Void, Void, Void> {
if(!PlayStationCertified.isPlaystationCertified(activity.getApplicationContext()))
installButton.setText("Install PS Certify");
else if(!Helper.isPsmInstalled(activity))
else if(!PsmApplication.isPsmInstalled(activity))
installButton.setText("Install PSM");
else if(Helper.isNoPsmDrmAlreadyInstalled(activity))
installButton.setText("Update NoPsmDrm");
else if(NoPsmDrmInstaller.isNoPsmDrmInstalled(activity))
installButton.setText("Repair NoPsmDrm");
else
installButton.setText("Install NoPsmDrm");
}
@ -43,64 +38,49 @@ public class Startup extends AsyncTask<Void, Void, Void> {
updateNames(activity);
}
public Startup(Activity context) {
this.handler = new Handler(context.getMainLooper());
this.ctx = context;
}
@Override
protected Void doInBackground(Void... params) {
try {
public static void runStartupCheck(Activity activity) {
Handler handler = new Handler(activity.getMainLooper());
TextView statusTV = (TextView) activity.findViewById(R.id.errorMsg);
Button installButton = (Button) activity.findViewById(R.id.installPsm);
if(!Root.init(ctx)){
wasError = true;
errorMsg = "Unable to get root permission.";
return null;
new Thread(() -> {
try {
Files.cleanupFiles(activity);
if (!Root.init(activity)) {
handler.post(() -> { statusTV.setText("Unable to get root permission."); });
return;
}
if (PsmApplication.isPsmInstalled(activity) && PsmApplication.getPsmAppPkg(activity).versionCode != 1170) {
handler.post(() -> { statusTV.setText("PSM Application is installed, but an older version, please update to 1.7.0 (have: " + String.valueOf(PsmApplication.getPsmVersion(activity)) + ")");});
return;
}
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
handler.post(() -> { statusTV.setText("No SD Card inserted.");});
}
Permissions.requestPermissions(activity);
PsmApplication.killPsm(activity);
handler.post(() -> {
statusTV.setText("");
if(NoPsmDrmInstaller.isNoPsmDrmInstalled(activity)){
setPsmInstalled(activity);
};
updateNames(activity);
installButton.setEnabled(true);
});
} catch (Exception e) {
handler.post(() ->{
statusTV.setText(e.getMessage());
});
}
if(Helper.isPsmInstalled(ctx) && Helper.getPsmAppPkg(ctx).versionCode != 1170) {
wasError = true;
errorMsg = "PSM Application is installed, but an older version, please update to 1.7.0 (have: "+String.valueOf(Helper.getPsmAppPkg(ctx).versionCode)+")";
return null;
}
if(!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
wasError = true;
errorMsg = "No SD Card inserted.";
return null;
}
Permissions.requestPermissions(this.ctx);
Helper.killPsm(ctx);
} catch (Exception e) {
wasError = true;
errorMsg = e.getMessage();
}
return null;
}).start();
}
@Override
protected void onPostExecute(Void result) {
TextView statusTV = (TextView) ((Activity)ctx).findViewById(R.id.errorMsg);
Button installButton = (Button) ((Activity)ctx).findViewById(R.id.installPsm);
if(!wasError) {
handler.post(() -> {
statusTV.setText("");
if(Helper.isNoPsmDrmAlreadyInstalled(ctx)){
setPsmInstalled(ctx);
};
updateNames(ctx);
installButton.setEnabled(true);
});
}
else{
handler.post(() -> {
statusTV.setText("Error: " + errorMsg);
});
}
}
}
}

View File

@ -0,0 +1,22 @@
package com.psmreborn.nopsmdrm.library_db;
import java.util.Arrays;
import java.util.List;
public class DownloadTableEntry extends TableEntryBase {
@Override
public final String tableName() {
return "DownloadTable";
}
@Override
protected final List<String> tableRows() {
return Arrays.asList("req_date", "stat", "progress", "dlm_id", "size", "need_wifi");
}
@Override
protected final List<String> tableTypes() {
return Arrays.asList("integer default 0", "integer default 0", "integer default 0", "integer", "integer default 0", "integer default 0");
}
}

View File

@ -0,0 +1,58 @@
package com.psmreborn.nopsmdrm.library_db;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class LibraryDbOpenHelper extends SQLiteOpenHelper {
public LibraryTableEntry libraryTableEntries;
public DownloadTableEntry downloadTableEntries;
public MetadataTableEntry metadataTableEntries;
private Context ctx = null;
private void createTables(SQLiteDatabase sqlDb) {
sqlDb.execSQL(getLibraryTableEntries().createTable());
sqlDb.execSQL(getDownloadTableEntries().createTable());
sqlDb.execSQL(getMetadataTableEntries().createTable());
}
private LibraryTableEntry getLibraryTableEntries() {
if (this.libraryTableEntries == null) {
this.libraryTableEntries = new LibraryTableEntry();
}
return this.libraryTableEntries;
}
private DownloadTableEntry getDownloadTableEntries() {
if (this.downloadTableEntries == null) {
this.downloadTableEntries = new DownloadTableEntry();
}
return this.downloadTableEntries;
}
private MetadataTableEntry getMetadataTableEntries() {
if (this.metadataTableEntries == null) {
this.metadataTableEntries = new MetadataTableEntry();
}
return this.metadataTableEntries;
}
public LibraryDbOpenHelper(Context context) {
super(context, "library.db", (SQLiteDatabase.CursorFactory) null, 2);
this.ctx = context;
}
@Override
public void onCreate(SQLiteDatabase sqlDb) {
createTables(sqlDb);
}
@Override
public void onUpgrade(SQLiteDatabase sqlDb, int i, int i1) {
if (i <= 1) {
sqlDb.execSQL(getLibraryTableEntries().dropTable());
sqlDb.execSQL(getDownloadTableEntries().dropTable());
sqlDb.execSQL(getMetadataTableEntries().dropTable());
createTables(sqlDb);
}
}
}

View File

@ -0,0 +1,22 @@
package com.psmreborn.nopsmdrm.library_db;
import java.util.Arrays;
import java.util.List;
public class LibraryTableEntry extends TableEntryBase {
@Override
public final String tableName() {
return "LibraryTable";
}
@Override
protected final List<String> tableRows() {
return Arrays.asList("update_date", "last_play", "reg_date", "content_id", "location_use_confirmation_date");
}
@Override
protected final List<String> tableTypes() {
return Arrays.asList("integer default 0", "integer default 0", "integer default 0", "text", "integer");
}
}

View File

@ -0,0 +1,22 @@
package com.psmreborn.nopsmdrm.library_db;
import java.util.Arrays;
import java.util.List;
public class MetadataTableEntry extends TableEntryBase {
@Override
public final String tableName() {
return "MetaDataTable";
}
@Override
protected final List<String> tableRows() {
return Arrays.asList("app_ver", "run_ver", "p_lock", "genre", "web", "copyright", "l_code", "r_code", "app_name", "app_s_name", "dev_name");
}
@Override
protected final List<String> tableTypes() {
return Arrays.asList("text", "text", "integer", "text", "text", "text", "text", "text", "text", "text", "text");
}
}

View File

@ -0,0 +1,51 @@
package com.psmreborn.nopsmdrm.library_db;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public abstract class TableEntryBase {
protected abstract String tableName();
protected abstract List<String> tableRows();
protected abstract List<String> tableTypes();
private HashMap<String, String> defaultTypes() {
HashMap<String, String> defaultsMap = new HashMap<String, String>();
defaultsMap.put("_id", "integer primary key autoincrement");
defaultsMap.put("enable", "integer default 1");
defaultsMap.put("title_id", "text unique");
List<String> tableRows = tableRows();
List<String> tableDefaults = tableTypes();
for (int i = 0; i < tableRows.size(); i++) {
defaultsMap.put(tableRows.get(i), tableDefaults.get(i));
}
return defaultsMap;
}
private ArrayList<String> defaultEntries() {
ArrayList<String> defaultsList = new ArrayList<String>();
defaultsList.add("_id");
defaultsList.add("enable");
defaultsList.add("title_id");
defaultsList.addAll(tableRows());
return defaultsList;
}
public final String createTable() {
StringBuilder sqlCommand = new StringBuilder(String.format("create table %s (", tableName()));
ArrayList<String> defaultEntries = defaultEntries();
HashMap<String, String> defaultDefaults = defaultTypes();
sqlCommand.append((String) defaultEntries.get(0)).append(" ").append((String) defaultDefaults.get(defaultEntries.get(0)));
for (int i = 1; i < defaultEntries.size(); i++) {
sqlCommand.append(String.format(",%s %s", defaultEntries.get(i), defaultDefaults.get(defaultEntries.get(i))));
}
sqlCommand.append(")");
return sqlCommand.toString();
}
public final String dropTable() {
return String.format("drop table %s;", tableName());
}
}

View File

@ -3,28 +3,27 @@ package com.psmreborn.pscertified;
import android.content.Context;
import android.os.Build;
import java.util.Arrays;
import java.util.HashSet;
public class PlayStationCertified {
private static CertifiedDeviceList[] certifiedDevices = {
new CertifiedDeviceList("Sony", new CertifiedDeviceEntry[] {new CertifiedDeviceEntry("SO-02E"), new CertifiedDeviceEntry("C6602"), new CertifiedDeviceEntry("C6603"), new CertifiedDeviceEntry("C6616"), new CertifiedDeviceEntry("C6606"), new CertifiedDeviceEntry("SOL22"), new CertifiedDeviceEntry("C6502"), new CertifiedDeviceEntry("C6503"), new CertifiedDeviceEntry("C6506"), new CertifiedDeviceEntry("SGP321"), new CertifiedDeviceEntry("SGP312"), new CertifiedDeviceEntry("SGP311"), new CertifiedDeviceEntry("SGP341"), new CertifiedDeviceEntry("SO-03E"), new CertifiedDeviceEntry("SGP351"), new CertifiedDeviceEntry("SO-04E"), new CertifiedDeviceEntry("C5503"), new CertifiedDeviceEntry("C5502"), new CertifiedDeviceEntry("L36h"), new CertifiedDeviceEntry("L35h"), new CertifiedDeviceEntry("M36h"), new CertifiedDeviceEntry("C5303"), new CertifiedDeviceEntry("C5306"), new CertifiedDeviceEntry("C5302"), new CertifiedDeviceEntry("M35h"), new CertifiedDeviceEntry("M35c"), new CertifiedDeviceEntry("C2105"), new CertifiedDeviceEntry("C2104"), new CertifiedDeviceEntry("S36h"), new CertifiedDeviceEntry("C1904"), new CertifiedDeviceEntry("C1905"), new CertifiedDeviceEntry("C2004"), new CertifiedDeviceEntry("C2005"), new CertifiedDeviceEntry("SOL23"), new CertifiedDeviceEntry("C6903"), new CertifiedDeviceEntry("SO-01F"), new CertifiedDeviceEntry("C6906"), new CertifiedDeviceEntry("C6902"), new CertifiedDeviceEntry("C6916"), new CertifiedDeviceEntry("C6833"), new CertifiedDeviceEntry("C6806"), new CertifiedDeviceEntry("C6802"), new CertifiedDeviceEntry("SOL24"), new CertifiedDeviceEntry("SGP412"), new CertifiedDeviceEntry("SO-02F"), new CertifiedDeviceEntry("D5503"), new CertifiedDeviceEntry("SO-04F"), new CertifiedDeviceEntry("C6843"), new CertifiedDeviceEntry("XL39h"), new CertifiedDeviceEntry("M51w"), new CertifiedDeviceEntry("D5303"), new CertifiedDeviceEntry("D5322"), new CertifiedDeviceEntry("D5306"), new CertifiedDeviceEntry("D5316"), new CertifiedDeviceEntry("D5316N"), new CertifiedDeviceEntry("D2303"), new CertifiedDeviceEntry("D2306"), new CertifiedDeviceEntry("D2305"), new CertifiedDeviceEntry("D2302"), new CertifiedDeviceEntry("D2403"), new CertifiedDeviceEntry("D2406"), new CertifiedDeviceEntry("S50h"), new CertifiedDeviceEntry("D6502"), new CertifiedDeviceEntry("D6503"), new CertifiedDeviceEntry("SO-03F"), new CertifiedDeviceEntry("D6543"), new CertifiedDeviceEntry("SOL25"), new CertifiedDeviceEntry("D6563"), new CertifiedDeviceEntry("SGP541"), new CertifiedDeviceEntry("SGP521"), new CertifiedDeviceEntry("SO-05F"), new CertifiedDeviceEntry("SOT21"), new CertifiedDeviceEntry("SGP551"), new CertifiedDeviceEntry("SGP511"), new CertifiedDeviceEntry("SGP512"), new CertifiedDeviceEntry("D6542"), new CertifiedDeviceEntry("M35t"), new CertifiedDeviceEntry("M35ts"), new CertifiedDeviceEntry("SO-01C"), new CertifiedDeviceEntry("SO-02C"), new CertifiedDeviceEntry("SO-02D"), new CertifiedDeviceEntry("SO-03D"), new CertifiedDeviceEntry("IS12S"), new CertifiedDeviceEntry("LT26i") }), new CertifiedDeviceList("Sony Ericsson", new CertifiedDeviceEntry[] { new CertifiedDeviceEntry("R800i"), new CertifiedDeviceEntry("R800a"), new CertifiedDeviceEntry("R800x"), new CertifiedDeviceEntry("R800at") }),
new CertifiedDeviceList("Sony", new CertifiedDeviceEntry[] {new CertifiedDeviceEntry("SO-02E"), new CertifiedDeviceEntry("C6602"), new CertifiedDeviceEntry("C6603"), new CertifiedDeviceEntry("C6616"), new CertifiedDeviceEntry("C6606"), new CertifiedDeviceEntry("SOL22"), new CertifiedDeviceEntry("C6502"), new CertifiedDeviceEntry("C6503"), new CertifiedDeviceEntry("C6506"), new CertifiedDeviceEntry("SGP321"), new CertifiedDeviceEntry("SGP312"), new CertifiedDeviceEntry("SGP311"), new CertifiedDeviceEntry("SGP341"), new CertifiedDeviceEntry("SO-03E"), new CertifiedDeviceEntry("SGP351"), new CertifiedDeviceEntry("SO-04E"), new CertifiedDeviceEntry("C5503"), new CertifiedDeviceEntry("C5502"), new CertifiedDeviceEntry("L36h"), new CertifiedDeviceEntry("L35h"), new CertifiedDeviceEntry("M36h"), new CertifiedDeviceEntry("C5303"), new CertifiedDeviceEntry("C5306"), new CertifiedDeviceEntry("C5302"), new CertifiedDeviceEntry("M35h"), new CertifiedDeviceEntry("M35c"), new CertifiedDeviceEntry("C2105"), new CertifiedDeviceEntry("C2104"), new CertifiedDeviceEntry("S36h"), new CertifiedDeviceEntry("C1904"), new CertifiedDeviceEntry("C1905"), new CertifiedDeviceEntry("C2004"), new CertifiedDeviceEntry("C2005"), new CertifiedDeviceEntry("SOL23"), new CertifiedDeviceEntry("C6903"), new CertifiedDeviceEntry("SO-01F"), new CertifiedDeviceEntry("C6906"), new CertifiedDeviceEntry("C6902"), new CertifiedDeviceEntry("C6916"), new CertifiedDeviceEntry("C6833"), new CertifiedDeviceEntry("C6806"), new CertifiedDeviceEntry("C6802"), new CertifiedDeviceEntry("SOL24"), new CertifiedDeviceEntry("SGP412"), new CertifiedDeviceEntry("SO-02F"), new CertifiedDeviceEntry("D5503"), new CertifiedDeviceEntry("SO-04F"), new CertifiedDeviceEntry("C6843"), new CertifiedDeviceEntry("XL39h"), new CertifiedDeviceEntry("M51w"), new CertifiedDeviceEntry("D5303"), new CertifiedDeviceEntry("D5322"), new CertifiedDeviceEntry("D5306"), new CertifiedDeviceEntry("D5316"), new CertifiedDeviceEntry("D5316N"), new CertifiedDeviceEntry("D2303"), new CertifiedDeviceEntry("D2306"), new CertifiedDeviceEntry("D2305"), new CertifiedDeviceEntry("D2302"), new CertifiedDeviceEntry("D2403"), new CertifiedDeviceEntry("D2406"), new CertifiedDeviceEntry("S50h"), new CertifiedDeviceEntry("D6502"), new CertifiedDeviceEntry("D6503"), new CertifiedDeviceEntry("SO-03F"), new CertifiedDeviceEntry("D6543"), new CertifiedDeviceEntry("SOL25"), new CertifiedDeviceEntry("D6563"), new CertifiedDeviceEntry("SGP541"), new CertifiedDeviceEntry("SGP521"), new CertifiedDeviceEntry("SO-05F"), new CertifiedDeviceEntry("SOT21"), new CertifiedDeviceEntry("SGP551"), new CertifiedDeviceEntry("SGP511"), new CertifiedDeviceEntry("SGP512"), new CertifiedDeviceEntry("D6542"), new CertifiedDeviceEntry("M35t"), new CertifiedDeviceEntry("M35ts"), new CertifiedDeviceEntry("SO-01C"), new CertifiedDeviceEntry("SO-02C"), new CertifiedDeviceEntry("SO-02D"), new CertifiedDeviceEntry("SO-03D"), new CertifiedDeviceEntry("IS12S"), new CertifiedDeviceEntry("LT26i") }),
new CertifiedDeviceList("Sony Ericsson", new CertifiedDeviceEntry[] { new CertifiedDeviceEntry("R800i"), new CertifiedDeviceEntry("R800a"), new CertifiedDeviceEntry("R800x"), new CertifiedDeviceEntry("R800at") }),
new CertifiedDeviceList("HTC", new CertifiedDeviceEntry[] { new CertifiedDeviceEntry("primou", 15) }),
new CertifiedDeviceList("SHARP", new CertifiedDeviceEntry[] { new CertifiedDeviceEntry("SH09D", 15), new CertifiedDeviceEntry("SHI16", 15) , new CertifiedDeviceEntry("SBM106SH", 15) , new CertifiedDeviceEntry("SBM203SH", 16) }),
new CertifiedDeviceList("FUJITSU MOBILE COMMUNICATIONS LIMITED", new CertifiedDeviceEntry[] { new CertifiedDeviceEntry("F05E", 15) }),
};
private static boolean isInDeviceList() {
String brand = Build.BRAND;
String device = Build.DEVICE;
String manufacturer = Build.MANUFACTURER;
int osVer = Build.VERSION.SDK_INT;
for(int i = 0; i < certifiedDevices.length; i++){
if(certifiedDevices[i].checkDevice(manufacturer, brand, osVer)){
if(certifiedDevices[i].checkDevice(manufacturer, device, osVer)){
return true;
}
}

View File

@ -11,8 +11,6 @@ import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Handler;
@ -21,90 +19,78 @@ import java.io.IOException;
import eu.chainfire.libsuperuser.Shell;
public class PsCertificatesInstaller extends AsyncTask<Void, Void, Void> {
private ProgressDialog dialog = null;
private boolean wasError = false;
private String errorMsg = "";
private Context ctx = null;
public class PsCertificatesInstaller {
public void installPlaystationCertificationMagisk() throws Exception {
private static void installPlaystationCertificationMagisk(Context ctx) throws Exception {
File magiskZip = new File(ctx.getCacheDir(), "MagiskCertify.zip");
Files.unpackResource(ctx, R.raw.magiskcertify, magiskZip);
Root.installMagiskModule(magiskZip.getAbsolutePath());
}
public void installPlaystationCertification() throws IOException, Shell.ShellDiedException {
private static void installPlaystationCertification(Context ctx) throws IOException, Shell.ShellDiedException {
// remount /system as read-write
remountRw("/system");
String psCertifiedPermissionFile = "/system/etc/permissions/com.playstation.playstationcertified.xml";
String psCertifiedJarFile = "/system/framework/com.playstation.playstationcertified.jar";
// remount partitions as read-write
remountRw(psCertifiedPermissionFile);
remountRw(psCertifiedJarFile);
Root.unpackResourceToLocationRoot(ctx, R.raw.ps_certified_permission, psCertifiedPermissionFile, 644, "0");
Root.unpackResourceToLocationRoot(ctx, R.raw.ps_certified_jar, psCertifiedJarFile, 644, "0");
// make it read-only again.
remountRo("/system");
remountRo(psCertifiedPermissionFile);
remountRo(psCertifiedJarFile);
}
public PsCertificatesInstaller(Context context) {
this.ctx = context;
}
@Override
protected void onPreExecute() {
dialog = new ProgressDialog(ctx);
public static void installPsCertificates(Activity activity) {
ProgressDialog dialog = new ProgressDialog(activity);
dialog.setTitle("Installing PlayStation Certificates ...");
dialog.setMessage("Please Wait ...");
dialog.setIndeterminate(true);
dialog.setCancelable(false);
dialog.show();
}
@Override
protected Void doInBackground(Void... voids) {
try {
if(Build.VERSION.SDK_INT >= 23) {
installPlaystationCertificationMagisk();
Handler handler = new Handler(activity.getMainLooper());
new Thread(() -> {
try {
if(Root.isMagiskRoot()) {
installPlaystationCertificationMagisk(activity);
}
else{
installPlaystationCertification(activity);
}
handler.post(() -> {
dialog.dismiss();
new AlertDialog.Builder(activity)
.setTitle("Installed!")
.setMessage("Your device is now \"Playstation Certified\"\n(You have to reboot for changes to take effect)\nDo you want to reboot?")
.setCancelable(false)
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
try {
Root.reboot();
} catch (Shell.ShellDiedException ignored) { }
}
})
.setNegativeButton("No", null).show();
});
}
else{
installPlaystationCertification();
catch(Exception e){
handler.post(() -> {
dialog.dismiss();
new AlertDialog.Builder(activity)
.setTitle("Error Occurred.")
.setMessage(e.toString())
.setCancelable(false)
.setPositiveButton("Ok",null).show();
});
}
}
catch(Exception e){
this.wasError = true;
this.errorMsg = e.getMessage();
return null;
}
return null;
}).start();
}
@Override
protected void onPostExecute(Void result) {
dialog.dismiss();
if(wasError) {
new AlertDialog.Builder((Activity)ctx)
.setTitle("Error Occurred.")
.setMessage(this.errorMsg)
.setCancelable(false)
.setPositiveButton("Ok",null).show();
}
else{
new AlertDialog.Builder((Activity)ctx)
.setTitle("Installed!")
.setMessage("Your device is now \"Playstation Certified\"\n(You have to reboot for changes to take effect)\nDo you want to reboot?")
.setCancelable(false)
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Handler handler = new Handler(PsCertificatesInstaller.this.ctx.getMainLooper());
handler.post(() -> {
try {
Root.reboot();
} catch (Shell.ShellDiedException e) {}
});
}
})
.setNegativeButton("No", null).show();
}
}
}

View File

@ -17,10 +17,7 @@ import java.io.InputStream;
import java.io.OutputStream;
public class Downloader {
static boolean wasError = false;
static String errorMsg = "";
private static void showErrorMessage(Activity ctx){
private static void showErrorMessage(Activity ctx, String errorMsg){
new AlertDialog.Builder(ctx)
.setTitle("Error Occurred.")
.setMessage(errorMsg)
@ -71,26 +68,23 @@ public class Downloader {
new Thread(() -> {
Handler handler = new Handler(ctx.getMainLooper());
Helper.killPsm(ctx);
PsmApplication.killPsm(ctx);
try {
download(url, saveLocation);
handler.post(() -> {dialog.setTitle("Installing "+filename+"...");});
Root.installRoot(saveLocation);
} catch (Exception e) {
wasError = true;
errorMsg = e.toString();
handler.post(() -> {
dialog.dismiss();
showErrorMessage(ctx, e.toString());
});
return;
}
handler.post(() -> {
dialog.dismiss();
Startup.updateNames(ctx);
if(wasError){
showErrorMessage(ctx);
}
else {
showInstallSuccessMsg(ctx, filename);
}
showInstallSuccessMsg(ctx, filename);
});
}).start();
@ -108,24 +102,21 @@ public class Downloader {
new Thread(() -> {
Handler handler = new Handler(ctx.getMainLooper());
Helper.killPsm(ctx);
PsmApplication.killPsm(ctx);
try {
download(url, saveLocation);
} catch (IOException e) {
wasError = true;
errorMsg = e.toString();
handler.post(() -> {
dialog.dismiss();
showErrorMessage(ctx, e.toString());
return;
});
}
handler.post(() -> {
dialog.dismiss();
Startup.updateNames(ctx);
if(wasError){
showErrorMessage(ctx);
}
else {
showDownloadSuccessMsg(ctx, filename);
}
showDownloadSuccessMsg(ctx, filename);
});
}).start();

View File

@ -1,6 +1,7 @@
package com.psmreborn.shared;
import android.content.Context;
import android.content.pm.PackageManager;
import android.util.Log;
import java.io.File;
@ -11,8 +12,29 @@ import java.io.InputStream;
import java.io.OutputStream;
public class Files {
public static void cleanupFiles(Context ctx) throws PackageManager.NameNotFoundException {
File databasesFolder = new File(Packages.getAppInfo(ctx, ctx.getPackageName()).dataDir, "databases");
Log.d("FILES", "DatabaseFolder: "+databasesFolder);
if(databasesFolder.exists()){
for(String db : databasesFolder.list()){
Log.d("FILES", "Deleting: "+db);
new File(databasesFolder, db).delete();
}
}
File sharedPrefFolder = new File(Packages.getAppInfo(ctx, ctx.getPackageName()).dataDir, "shared_prefs");
Log.d("FILES", "SharedPrefsFolder: "+sharedPrefFolder);
if(sharedPrefFolder.exists()){
for(String pref : sharedPrefFolder.list()){
Log.d("FILES", "Deleting: "+pref);
new File(sharedPrefFolder, pref).delete();
}
}
}
public static void unpackResource(Context ctx, int resourceId, File outputFile) throws IOException {
Log.i("ROOT", "Unpacking resource to : " + outputFile);
Log.i("FILES", "Unpacking resource to : " + outputFile);
InputStream resourceStream = ctx.getResources().openRawResource(resourceId);
FileOutputStream fs = new FileOutputStream(outputFile, false);
@ -22,7 +44,7 @@ public class Files {
resourceStream.close();
}
public static void writeTxtFile(String txtFile, String txt) throws IOException {
Log.i("ROOT", "Writing: " + txtFile);
Log.i("FILES", "Writing: " + txtFile);
FileWriter txtStream = new FileWriter(txtFile);
txtStream.write(txt);
txtStream.close();

View File

@ -1,174 +0,0 @@
package com.psmreborn.shared;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.ActivityManager;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.provider.Settings;
import com.psmreborn.nopsmdrm.R;
import com.rosstonovsky.abxutils.BinaryXmlPullParser;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Helper {
private static final String psmAppPackage = "com.playstation.psstore";
public static boolean isNoPsmDrmAlreadyInstalled(Context ctx) {
try {
if(new File(getPsmAppInfo(ctx).nativeLibraryDir, "libdefault_real.so").exists()){
return true;
}
} catch (PackageManager.NameNotFoundException e) {
return false;
}
return false;
}
public static long getDefaultAccountId(Context ctx){
return Long.valueOf(ctx.getResources().getString(R.string.default_account_id), 16);
}
public static String getSharedPrefFromPsm(Context ctx, String prefName, String prefKey) throws Exception {
String psmSharedPrefs = new File(Helper.getPsmAppInfo(ctx).dataDir, "shared_prefs").getAbsolutePath();
String psmPrefFile = new File(psmSharedPrefs, prefName+".xml").getAbsolutePath();
String mySharedPrefs = new File(Helper.getAppInfo(ctx, ctx.getPackageName()).dataDir, "shared_prefs").getAbsolutePath();
String myPrefFile = new File(mySharedPrefs, prefName+".xml").getAbsolutePath();
Root.mkdirAndChmodChown(mySharedPrefs, 771, String.valueOf(Helper.getMyUid(ctx)));
Root.copyChmodAndChown(psmPrefFile, myPrefFile, 660, String.valueOf(Helper.getMyUid(ctx)));
SharedPreferences pref = ctx.getSharedPreferences(prefName, 0);
return pref.getString(prefKey, null);
}
public static boolean isPsmInstalled(Context ctx){
try {
ctx.getPackageManager().getApplicationInfo(psmAppPackage, 0);
} catch (PackageManager.NameNotFoundException e) {
return false;
}
return true;
}
private static String parseSsaidText(FileInputStream stream) throws XmlPullParserException, IOException {
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
factory.setNamespaceAware(false);
XmlPullParser xpp = factory.newPullParser();
xpp.setInput(stream, "UTF-8");
int eventType = xpp.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
if(eventType == XmlPullParser.START_TAG) {
if(xpp.getName().equalsIgnoreCase("setting")){
String packageName = xpp.getAttributeValue(null,"package");
if(packageName != null && packageName.equalsIgnoreCase("com.playstation.psstore")){
return xpp.getAttributeValue(null,"value");
}
}
}
eventType = xpp.next();
}
return null;
}
private static String parseSsaidBinary(FileInputStream stream) throws XmlPullParserException, IOException {
// parse binary xml file ...
BinaryXmlPullParser xpp = new BinaryXmlPullParser();
xpp.setInput(stream, "UTF-8");
int eventType = xpp.getEventType();
while (eventType != BinaryXmlPullParser.END_DOCUMENT) {
if(eventType == BinaryXmlPullParser.START_TAG) {
if(xpp.getName().equalsIgnoreCase("setting")){
String packageName = xpp.getAttributeValue("package");
if(packageName != null && packageName.equalsIgnoreCase("com.playstation.psstore")){
return xpp.getAttributeValue("value");
}
}
}
eventType = xpp.next();
}
return null;
}
@SuppressLint("HardwareIds")
public static String getAndroidIdOfPsm(Context ctx) throws Exception {
if(Build.VERSION.SDK_INT >= 26){
String[] files = Root.findFiles("/data/system", "settings_ssaid.xml");
File ssaidCacheFile = new File(ctx.getCacheDir(), "settings_ssaid.xml");
for(String ssaidFile : files){
Root.copyChmodAndChown(ssaidFile, ssaidCacheFile.getAbsolutePath(), 777, String.valueOf(Helper.getMyUid(ctx)));
try{
FileInputStream stream = new FileInputStream(ssaidCacheFile);
return parseSsaidBinary(stream);
}
catch (XmlPullParserException e){
FileInputStream stream = new FileInputStream(ssaidCacheFile);
return parseSsaidText(stream);
}
}
return null;
}
else {
return Settings.Secure.getString(ctx.getContentResolver(), "android_id");
}
}
public static int getMyUid(Context ctx) {
try{
ApplicationInfo myAppInfo = ctx.getPackageManager().getApplicationInfo(ctx.getPackageName(), 0);
if(myAppInfo != null) {
return myAppInfo.uid;
}
}
catch (PackageManager.NameNotFoundException e) { };
return 0;
}
public static int getPsmUid(Context ctx) {
try{
ApplicationInfo psmAppInfo = ctx.getPackageManager().getApplicationInfo(psmAppPackage, 0);
if(psmAppInfo != null) {
return psmAppInfo.uid;
}
}
catch (PackageManager.NameNotFoundException e) { };
return 0;
}
public static void killPsm(Context ctx){
ActivityManager am = (ActivityManager) ctx.getSystemService(Activity.ACTIVITY_SERVICE);
if (am != null) {
am.killBackgroundProcesses(psmAppPackage);
}
}
public static PackageInfo getPackageInfo(Context ctx, String pkg) throws PackageManager.NameNotFoundException {
return ctx.getPackageManager().getPackageInfo(pkg, 0);
}
public static ApplicationInfo getAppInfo(Context ctx, String pkg) throws PackageManager.NameNotFoundException {
return ctx.getPackageManager().getApplicationInfo(pkg, 0);
}
public static PackageInfo getPsmAppPkg(Context ctx) throws PackageManager.NameNotFoundException {
return Helper.getPackageInfo(ctx,psmAppPackage);
}
public static ApplicationInfo getPsmAppInfo(Context ctx) throws PackageManager.NameNotFoundException {
return Helper.getAppInfo(ctx,psmAppPackage);
}
@SuppressLint("SimpleDateFormat")
public static String getDateTime(){
return new SimpleDateFormat("MM_dd_yyyy_HH_mm_ss").format(new Date());
}
}

View File

@ -15,10 +15,10 @@ public class Logger {
return new String(hexChars);
}
public static void logText(String description, String text){
Log.i("NoPsmDrmApp", description + " = "+text);
Log.i("NoPsmDrmApp", description.toUpperCase() + " = "+text);
}
public static void logBytes(String description, byte[] data){
Log.i("NoPsmDrmApp", description + " = " + bytesToHex(data));
Log.i("NoPsmDrmApp", description.toUpperCase() + " = " + bytesToHex(data));
}
}

View File

@ -0,0 +1,80 @@
package com.psmreborn.shared;
import android.util.Log;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
public class MountPoint {
private final HashSet<String> mountFlags = new HashSet<String>();
private final String filesystem;
private final String mountPoint;
public static MountPoint getMountPointAt(String path) {
try{
BufferedReader reader = new BufferedReader(new FileReader("/proc/mounts"));
String line = reader.readLine();
MountPoint mp = null;
do {
String[] mountParts = line.split(" ");
if(mountParts.length < 1) continue;
File gotMountPoint = new File(mountParts[1]);
String gotMountFs = mountParts[2];
String gotMountFlags = mountParts[3];
Log.d("MOUNTPOINT", gotMountPoint.getAbsolutePath());
// check if filepath is a child of this mount point.
File filePath = new File(path);
do{
if((filePath.equals(gotMountPoint)) && (mp == null || (gotMountPoint.getAbsolutePath().length() > mp.getMountPoint().length()))) {
mp = new MountPoint(gotMountPoint.getAbsolutePath(), gotMountFs, gotMountFlags);
}
filePath = filePath.getParentFile();
}while(filePath != null);
line = reader.readLine();
} while(line != null);
return mp;
}
catch (IOException e){
Log.e("MOUNTPOINT", e.toString());
return new MountPoint(path, "yaffs2", "rw");
}
}
public MountPoint(String point, String filesystem, String flags){
this.mountFlags.addAll(Arrays.asList(flags.split(",")));
this.mountPoint = point;
this.filesystem = filesystem;
}
public String getFilesystem() {
return filesystem;
}
public String getMountPoint() {
return mountPoint;
}
public boolean hasFlag(String flag){
return mountFlags.contains(flag);
}
public boolean isRw(){
return hasFlag("rw") && !hasFlag("ro");
}
public boolean isRo(){
return hasFlag("ro") && !hasFlag("rw");
}
public boolean isFat(){
return filesystem.contains("fat");
}
}

View File

@ -0,0 +1,75 @@
package com.psmreborn.shared;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.ActivityManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.provider.Settings;
import com.psmreborn.nopsmdrm.R;
import java.io.File;
public class Packages {
@SuppressLint("HardwareIds")
public static String getAndroidIdOfApp(Context ctx, String packageId) {
if(Build.VERSION.SDK_INT >= 26){
try{
String[] files = Root.findFiles("/data/system", "settings_ssaid.xml");
String ssaidCacheFile = new File(ctx.getCacheDir(), "settings_ssaid.xml").getAbsolutePath();
for(String ssaidFile : files){
try {
Root.copyChmodAndChown(ssaidFile, ssaidCacheFile, 777, String.valueOf(Packages.getAppUid(ctx, ctx.getPackageName())));
return SsaidParser.parseSsaid(ssaidCacheFile, packageId);
} catch (Exception e) {
continue;
}
}
}
catch (Exception e){
return null;
}
return null;
}
else {
return Settings.Secure.getString(ctx.getContentResolver(), "android_id");
}
}
public static void killApp(Context ctx, String packageName) {
if (Build.VERSION.SDK_INT >= 34) {
new Thread(() -> {
try {
Root.killProcess(packageName);
} catch (Exception e) {
return;
}
}).start();
} else {
ActivityManager am = (ActivityManager) ctx.getSystemService(Activity.ACTIVITY_SERVICE);
if (am != null) {
am.killBackgroundProcesses(packageName);
}
}
}
public static int getAppUid(Context ctx, String packageName){
try{
ApplicationInfo appInfo = ctx.getPackageManager().getApplicationInfo(packageName, 0);
if(appInfo != null) {
return appInfo.uid;
}
}
catch (PackageManager.NameNotFoundException ignored) { };
return 0;
}
public static PackageInfo getPackageInfo(Context ctx, String pkg) throws PackageManager.NameNotFoundException {
return ctx.getPackageManager().getPackageInfo(pkg, 0);
}
public static ApplicationInfo getAppInfo(Context ctx, String pkg) throws PackageManager.NameNotFoundException {
return ctx.getPackageManager().getApplicationInfo(pkg, 0);
}
}

View File

@ -0,0 +1,66 @@
package com.psmreborn.shared;
import android.app.Activity;
import android.app.ActivityManager;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import com.psmreborn.nopsmdrm.R;
import java.io.File;
public class PsmApplication {
public static int getPsmVersion(Context ctx){
try {
return PsmApplication.getPsmAppPkg(ctx).versionCode;
} catch (PackageManager.NameNotFoundException e) {
return 0;
}
}
public static boolean isPsmInstalled(Context ctx){
try {
ctx.getPackageManager().getApplicationInfo(ctx.getResources().getString(R.string.psm_app_package_id), 0);
} catch (PackageManager.NameNotFoundException e) {
return false;
}
return true;
}
public static int getPsmUid(Context ctx) {
return Packages.getAppUid(ctx, ctx.getResources().getString(R.string.psm_app_package_id));
}
public static void killPsm(Context ctx){
Packages.killApp(ctx, ctx.getResources().getString(R.string.psm_app_package_id));
}
public static PackageInfo getPsmAppPkg(Context ctx) throws PackageManager.NameNotFoundException {
return Packages.getPackageInfo(ctx,ctx.getResources().getString(R.string.psm_app_package_id));
}
public static ApplicationInfo getPsmAppInfo(Context ctx) throws PackageManager.NameNotFoundException {
return Packages.getAppInfo(ctx,ctx.getResources().getString(R.string.psm_app_package_id));
}
public static String getAndroidIdOfPsm(Context ctx){
return Packages.getAndroidIdOfApp(ctx, ctx.getResources().getString(R.string.psm_app_package_id));
}
public static String getSharedPrefFromPsm(Context ctx, String prefName, String prefKey) throws Exception {
String psmSharedPrefs = new File(getPsmAppInfo(ctx).dataDir, "shared_prefs").getAbsolutePath();
String psmPrefFile = new File(psmSharedPrefs, prefName+".xml").getAbsolutePath();
String mySharedPrefs = new File(Packages.getAppInfo(ctx, ctx.getPackageName()).dataDir, "shared_prefs").getAbsolutePath();
String myPrefFile = new File(mySharedPrefs, prefName+".xml").getAbsolutePath();
if(!Root.fileExistRoot(psmSharedPrefs)) return null;
Root.mkdirAndChmodChown(mySharedPrefs, 771, String.valueOf(Packages.getAppUid(ctx, ctx.getPackageName())));
Root.copyChmodAndChown(psmPrefFile, myPrefFile, 660, String.valueOf(Packages.getAppUid(ctx, ctx.getPackageName())));
SharedPreferences pref = ctx.getSharedPreferences(prefName, 0);
return pref.getString(prefKey, null);
}
}

View File

@ -2,12 +2,16 @@ package com.psmreborn.shared;
import android.content.Context;
import android.os.Build;
import android.os.Environment;
import android.util.Log;
import com.psmreborn.nopsmdrm.R;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
@ -20,6 +24,23 @@ import eu.chainfire.libsuperuser.Shell;
public class Root {
private static String busyboxBinary = null;
public static boolean isMagiskRoot() {
String[] pathLocations = System.getenv("PATH").split(":");
for(String pathLocation : pathLocations){
if(new File(pathLocation, "magisk").exists()){
return true;
}
}
return false;
}
public static void killProcess(String processName) throws Shell.ShellDiedException {
int res = 0;
do{
res = Shell.Pool.SU.run(new String[] { busyboxBinary + " pkill -9 '"+processName+"'" });
} while(res == 0);
}
public static void installMagiskModule(String magiskModuleFile) throws Exception {
int res = 0;
res = Shell.Pool.SU.run(new String[] { "magisk --install-module '"+magiskModuleFile+"'"});
@ -41,8 +62,14 @@ public class Root {
res = Shell.Pool.SU.run(new String[] { "pm install '"+apkFileName+"'" },results, null, true);
}
// delete apk now its installed.
deleteRoot(apkFileName);
// delete apk (for some reason this sometimes doesn't work, (file is in use somehow?) so we try a few times to remove it
for(int i = 0; i < 500; i++){
try{
deleteRoot(apkFileName);
break;
}
catch (Exception ignored) { }
}
if(res != 0) {
throw new Exception(results.get(0));
@ -52,7 +79,7 @@ public class Root {
Log.i("ROOT", "deleting file: "+filename);
int res = Shell.Pool.SU.run(new String[] { busyboxBinary + " rm -f '"+filename+"'" });
if(res != 0){
throw new IOException("failed to remove file.");
throw new IOException("failed to remove file \""+filename+"\"");
}
}
public static void reboot() throws Shell.ShellDiedException {
@ -102,7 +129,7 @@ public class Root {
return results.get(0);
}
Log.e("ROOT", "error (" + String.valueOf(res) +")");
throw new IOException("failed to get owner: "+filePath);
return null;
}
public static void tarRoot(ArrayList<String> src, String dst) throws IOException, Shell.ShellDiedException {
@ -127,18 +154,26 @@ public class Root {
}
public static void remountRo(String foldername) throws IOException, Shell.ShellDiedException {
Log.i("ROOT", "Remounting as RO: " + foldername);
int res = Shell.Pool.SU.run(new String[] { busyboxBinary +" mount -o ro,remount '"+foldername+"'"});
if(res != 0){
Log.e("ROOT", "error (" + String.valueOf(res) +")");
throw new IOException("Failed to remmount: "+foldername + " ("+String.valueOf(res)+")");
MountPoint mountPoint = MountPoint.getMountPointAt(foldername);
if(mountPoint.isRw()) {
int res = Shell.Pool.SU.run(new String[]{busyboxBinary + " mount -o ro,remount '" + mountPoint.getMountPoint() + "'"});
if (res != 0) {
Log.e("ROOT", "error (" + String.valueOf(res) + ")");
throw new IOException("Failed to remmount: " + foldername + " (" + String.valueOf(res) + ")");
}
}
}
public static void remountRw(String foldername) throws IOException, Shell.ShellDiedException {
Log.i("ROOT", "Remounting as RW: " + foldername);
int res = Shell.Pool.SU.run(new String[] { busyboxBinary +" mount -o rw,remount '"+foldername+"'"});
if(res != 0){
Log.e("ROOT", "error (" + String.valueOf(res) +")");
throw new IOException("Failed to remmount: "+foldername + " ("+String.valueOf(res)+")");
MountPoint mountPoint = MountPoint.getMountPointAt(foldername);
if(mountPoint.isRo()){
int res = Shell.Pool.SU.run(new String[] { busyboxBinary +" mount -o rw,remount '"+mountPoint.getMountPoint()+"'"});
if(res != 0){
Log.e("ROOT", "error (" + String.valueOf(res) +")");
throw new IOException("Failed to remmount: "+foldername + " ("+String.valueOf(res)+")");
}
}
}
public static void moveFileRoot(String filename, String destFilename) throws IOException, Shell.ShellDiedException {
@ -218,6 +253,7 @@ public class Root {
Log.i("ROOT", "Unpacking resource and root copying to : " + outputDir);
File tmpFile = File.createTempFile("tmp", "file", ctx.getCacheDir());
tmpFile.createNewFile();
tmpFile.deleteOnExit();
Files.unpackResource(ctx, resourceId, tmpFile);
moveChmodAndChown(tmpFile.getAbsolutePath(), outputDir, chmod, chown);
@ -225,19 +261,19 @@ public class Root {
private static void setupBusyBox(Context ctx) throws IOException {
Log.i("ROOT","Creating busybox binary");
File tmpFile = new File(ctx.getCacheDir(), "busybox");
if(!tmpFile.exists()) {
tmpFile.createNewFile();
File busyboxPath = new File(ctx.getCacheDir(), "busybox");
if(!busyboxPath.exists()) {
busyboxPath.createNewFile();
if(tmpFile.setExecutable(true,false)) {
Files.unpackResource(ctx, R.raw.busybox, tmpFile);
if(busyboxPath.setExecutable(true,false)) {
Files.unpackResource(ctx, R.raw.busybox, busyboxPath);
}
else {
throw new IOException("failed to extract busybox binary.");
}
}
busyboxBinary = tmpFile.getAbsolutePath();
busyboxBinary = busyboxPath.getAbsolutePath();
}
public static boolean init(Context ctx) throws IOException {

View File

@ -0,0 +1,67 @@
package com.psmreborn.shared;
import com.rosstonovsky.abxutils.BinaryXmlPullParser;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
import java.io.FileInputStream;
import java.io.IOException;
public class SsaidParser {
private static String parseSsaidText(FileInputStream stream, String searchPackage) throws XmlPullParserException, IOException {
// parse xml file ...
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
factory.setNamespaceAware(false);
XmlPullParser xpp = factory.newPullParser();
xpp.setInput(stream, "UTF-8");
int eventType = xpp.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
if(eventType == XmlPullParser.START_TAG) {
if(xpp.getName().equalsIgnoreCase("setting")){
String packageName = xpp.getAttributeValue(null,"package");
if(packageName != null && packageName.equalsIgnoreCase(searchPackage)){
return xpp.getAttributeValue(null,"value");
}
}
}
eventType = xpp.next();
}
return null;
}
private static String parseSsaidBinary(FileInputStream stream, String searchPackage) throws XmlPullParserException, IOException {
// parse binary xml file ...
BinaryXmlPullParser xpp = new BinaryXmlPullParser();
xpp.setInput(stream, "UTF-8");
int eventType = xpp.getEventType();
while (eventType != BinaryXmlPullParser.END_DOCUMENT) {
if(eventType == BinaryXmlPullParser.START_TAG) {
if(xpp.getName().equalsIgnoreCase("setting")){
String packageName = xpp.getAttributeValue("package");
if(packageName != null && packageName.equalsIgnoreCase(searchPackage)){
return xpp.getAttributeValue("value");
}
}
}
eventType = xpp.next();
}
return null;
}
public static String parseSsaid(String filename, String searchPackage) throws XmlPullParserException, IOException {
try{
FileInputStream stream = new FileInputStream(filename);
return parseSsaidBinary(stream, searchPackage);
}
catch (XmlPullParserException e){
FileInputStream stream = new FileInputStream(filename);
return parseSsaidText(stream, searchPackage);
}
}
}

View File

@ -44,7 +44,7 @@ public class StringEncryptor {
}
public String decryptString(String str, String def) {
if(str == null) return null;
if(str == null) return def;
byte[] data = decodeBase64(str);
byte[] arrayData = Arrays.copyOf(data, data.length - 2);

View File

@ -0,0 +1,199 @@
package com.psmreborn.xposed;
import android.content.Context;
import android.os.Build;
import android.text.TextUtils;
import android.util.Log;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam;
public class JavaPatch implements IXposedHookLoadPackage {
private void hookCdnUrls(LoadPackageParam lpparam) {
/*
* Fix CDN
*/
XposedHelpers.findAndHookMethod("com.playstation.psstore.util.db", lpparam.classLoader, "b", new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
Log.d("NoPssDrmXposed","versionInfoUrl called!");
param.setResult("http://zeus.dl.playstation.net/pss/store/update/versionInfo.dat");
}
});
Log.d("NoPssDrmXposed","versionInfoUrl hooked.");
XposedHelpers.findAndHookMethod("com.playstation.psstore.util.db", lpparam.classLoader, "c", new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
Log.d("NoPssDrmXposed","pssZpakCdn called!");
param.setResult("http://zeus.dl.playstation.net/pss/cGxheXN0YXRpb25z/");
}
});
Log.d("NoPssDrmXposed","pssZpakCdn hooked.");
XposedHelpers.findAndHookMethod("com.playstation.psstore.util.db", lpparam.classLoader, "d", new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
Log.d("NoPssDrmXposed","deviceList2Cdn called!");
param.setResult("http://zeus.dl.playstation.net/pss/store/manifest/deviceList2.dat");
}
});
Log.d("NoPssDrmXposed","deviceList2Cdn hooked.");
XposedHelpers.findAndHookMethod("com.playstation.psstore.util.db", lpparam.classLoader, "e", new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
Log.d("NoPssDrmXposed","comingSoonDevListUrl called!");
param.setResult("http://zeus.dl.playstation.net/psm/store/manifest/comingSoonDevList.dat");
}
});
Log.d("NoPssDrmXposed","comingSoonDevListUrl hooked.");
XposedHelpers.findAndHookMethod("com.playstation.psstore.util.db", lpparam.classLoader, "f", new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
Log.d("NoPssDrmXposed","comingSoonUrl called!");
param.setResult("http://zeus.dl.playstation.net/psm/store/manifest/comingSoon.dat");
}
});
Log.d("NoPssDrmXposed","comingSoonUrl hooked.");
XposedHelpers.findAndHookMethod("com.playstation.psstore.util.db", lpparam.classLoader, "g", new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
Log.d("NoPssDrmXposed","addtionalCertifiedDevListUrl called!");
param.setResult("http://zeus.dl.playstation.net/psm/store/manifest/addtionalCertifiedDevList.dat");
}
});
Log.d("NoPssDrmXposed","addtionalCertifiedDevListUrl hooked.");
}
private void hookTls(LoadPackageParam lpparam) {
/*
* Hook TLS
*/
XposedHelpers.findAndHookMethod("yl", lpparam.classLoader, "e", new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
Log.d("NoPssDrmXposed","shouldIgnoreTls called!");
param.setResult(true);
}
});
Log.d("NoPssDrmXposed","shouldIgnoreTls hooked.");
}
private void hookPlaystationCertifiedChecks(LoadPackageParam lpparam) {
/*
* PS1 CERTIFIED CHECK BYPASS
*/
// verifyWithPsSuiteCer
XposedHelpers.findAndHookMethod("com.playstation.psstore.util.ct", lpparam.classLoader, "a", Context.class, "com.playstation.psstore.util.cv", new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
Log.d("NoPssDrmXposed","verifyWithPsSuiteCer called!");
param.setResult(true);
}
});
Log.d("NoPssDrmXposed","verifyWithPsSuiteCer hooked.");
// getSupportedDevices
XposedHelpers.findAndHookMethod("com.playstation.psstore.util.de", lpparam.classLoader, "a", new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
Log.d("NoPssDrmXposed","getSupportedDevices called!");
// get Device Info Class.
Class<?> deviceInfoClass = XposedHelpers.findClass("com.playstation.psstore.util.dd", lpparam.classLoader); // com.playstation.psstore.util.DeviceInfo (deobfuscated name)
Log.d("NoPssDrmXposed","got deviceInfoClass "+deviceInfoClass.toString());
// get arraylist of supported devices
ArrayList<Object> supportedDevicesArray = (ArrayList<Object>)param.getResult();
Log.d("NoPssDrmXposed","got array!");
// get DeviceInfo constructor
Constructor<?> deviceInfoConstructor = deviceInfoClass.getDeclaredConstructor(String.class, String.class, String.class, String.class, int.class, int.class, boolean.class);
Log.d("NoPssDrmXposed","got constructor!");
// make it public
deviceInfoConstructor.setAccessible(true);
Log.d("NoPssDrmXposed","made constructor public!");
// create new object...
Object myDeviceInfo = deviceInfoConstructor.newInstance("PLAY", "PN.XPERIA", Build.BRAND, Build.DEVICE, -1, -1, true);
Log.d("NoPssDrmXposed","got new obj \""+myDeviceInfo.toString()+"\"!");
// add new deviceInfo to list of supported devices
supportedDevicesArray.add(myDeviceInfo);
Log.d("NoPssDrmXposed","add newObj to array!");
// set new array as result.
param.setResult(supportedDevicesArray);
}
});
Log.d("NoPssDrmXposed","getSupportedDevices hooked.");
}
private void hookWifiCheck(LoadPackageParam lpparam) {
/*
* WIFI CHECK BYPASS
*/
XposedHelpers.findAndHookMethod("li", lpparam.classLoader, "b", new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
Log.d("NoPssDrmXposed","appUpdateRequired: "+ param.getResult());
param.setResult(1);
}
});
XposedHelpers.findAndHookMethod("jd", lpparam.classLoader, "b", new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
Log.d("NoPssDrmXposed","wifiRequired: "+ param.getResult());
param.setResult(2);
}
});
XposedHelpers.findAndHookMethod("android.net.wifi.WifiInfo", lpparam.classLoader, "getMacAddress", new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
Log.d("NoPssDrmXposed","getMacAddress called!");
String macAddress = (String)param.getResult();
Log.d("NoPssDrmXposed", "got macAddress: \""+macAddress+"\"");
if(TextUtils.isEmpty(macAddress)) {
param.setResult("00:11:22:33:44:55");
}
}
});
Log.d("NoPssDrmXposed","getMacAddress hooked.");
}
public void handleLoadPackage(LoadPackageParam lpparam) throws Throwable {
if (!lpparam.packageName.equals("com.playstation.psstore"))
return;
if(lpparam.processName.equals("com.playstation.psstore:PsmApp"))
return;
Log.d("NoPssDrmXposed","Loaded app: " + lpparam.packageName + " // "+ lpparam.processName);
hookWifiCheck(lpparam);
hookPlaystationCertifiedChecks(lpparam);
hookCdnUrls(lpparam);
hookTls(lpparam);
}
}

View File

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -49,6 +49,6 @@
android:enabled="false"
android:layout_below="@+id/takeOwnership"
android:textColor="@color/white"
android:text="Backup all licenses" />
android:text="Backup all RIFs" />
</RelativeLayout>

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,8 +1,15 @@
<resources>
<string name="app_name">NoPssDrm</string>
<string name="name_nopsmdrm">NoPsmDrm</string>
<string name="name_nops1drm">NoPs1Drm</string>
<string name="name_nops1drm_ticket">NoPs1Drm - Ticket Generator</string>
<string name="name_nops1drm_update">NoPs1Drm - zPAK Updater</string>
<string name="default_email">nopsmdrm@transrights.lgbt</string>
<string name="default_password">password</string>
<string name="default_online_id">TransgenderPS1</string>
<string name="default_account_id">0123456789abcdef</string>
<string name="psm_app_package_id">com.playstation.psstore</string>
<string-array name="scope">
<item>com.playstation.psstore</item>
</string-array>
</resources>

View File

@ -3,4 +3,3 @@ plugins {
id 'com.android.application' version '8.3.2' apply false
id 'com.android.library' version '8.3.2' apply false
}

View File

@ -14,10 +14,12 @@ org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app's APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true
android.useAndroidX=false
# Enables namespacing of each library's R class so that its R class includes only the
# resources declared in the library itself and none from the library's dependencies,
# thereby reducing the size of the R class for that library
android.nonTransitiveRClass=true
# make it work how it used to ??
android.nonFinalResIds=false
applicationName = NoPssDrm

View File

@ -4,6 +4,7 @@ plugins {
android {
namespace 'com.rosstonovsky.abxutils'
//noinspection GradleDependency needs to work properly on android 2.x
compileSdk 10
defaultConfig {
@ -22,5 +23,6 @@ android {
}
dependencies {
implementation 'androidx.annotation:annotation-jvm:1.7.1'
//noinspection GradleDependency new version has min sdk 14
implementation 'com.android.support:support-core-utils:25.0.0'
}

View File

@ -35,8 +35,7 @@ import static com.rosstonovsky.abxutils.BinaryXmlSerializer.TYPE_STRING_INTERNED
import android.text.TextUtils;
import android.util.Base64;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import android.support.annotation.*;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

View File

@ -16,7 +16,7 @@
*/
package com.rosstonovsky.abxutils;
import androidx.annotation.NonNull;
import android.support.annotation.*;
import java.io.Closeable;
import java.io.DataInput;

View File

@ -16,8 +16,7 @@
*/
package com.rosstonovsky.abxutils;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import android.support.annotation.*;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

View File

@ -4,6 +4,7 @@ plugins {
android {
namespace 'eu.chainfire.libsuperuser'
//noinspection GradleDependency needs to work properly on android 2.x
compileSdk 10
defaultConfig {
@ -22,5 +23,6 @@ android {
}
dependencies {
implementation 'androidx.annotation:annotation-jvm:1.7.1'
//noinspection GradleDependency new version has min sdk 14
implementation 'com.android.support:support-core-utils:25.0.0'
}

View File

@ -20,9 +20,8 @@ import android.content.Context;
import android.os.Handler;
import android.widget.Toast;
import androidx.annotation.AnyThread;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import android.support.annotation.*;
/**
* Base application class to extend from, solving some issues with

View File

@ -20,9 +20,8 @@ import android.os.Looper;
import android.util.Log;
import android.os.Process;
import androidx.annotation.AnyThread;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import android.support.annotation.*;
/**
* Utility class for logging and debug features that (by default) does nothing when not in debug mode

View File

@ -20,9 +20,8 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import androidx.annotation.AnyThread;
import androidx.annotation.NonNull;
import androidx.annotation.WorkerThread;
import android.support.annotation.*;
@SuppressWarnings("WeakerAccess")
@AnyThread

View File

@ -19,10 +19,8 @@ package eu.chainfire.libsuperuser;
import java.util.ArrayList;
import java.util.List;
import androidx.annotation.AnyThread;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
import android.support.annotation.*;
/**
* Helper class for modifying SELinux policies, reducing the number of calls to a minimum.

View File

@ -42,10 +42,7 @@ import java.util.concurrent.TimeUnit;
import java.lang.Object;
import java.lang.String;
import androidx.annotation.AnyThread;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
import android.support.annotation.*;
import eu.chainfire.libsuperuser.StreamGobbler.OnLineListener;
import eu.chainfire.libsuperuser.StreamGobbler.OnStreamClosedListener;

View File

@ -23,10 +23,8 @@ import java.io.InputStreamReader;
import java.util.List;
import java.util.Locale;
import androidx.annotation.AnyThread;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
import android.support.annotation.*;
/**
* Thread utility class continuously reading from an InputStream

View File

@ -21,9 +21,7 @@ import android.os.Build;
import java.util.List;
import java.util.Locale;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
import android.support.annotation.*;
/**
* Utility class to decide between toolbox and toybox calls on M.

View File

@ -1,43 +1,67 @@
-- How to use it?
## How to use it?
Android 2.3.3+ is required.
Your device must be rooted & on android 2.3.0 or later.
Your device must be rooted.
If you cannot root your device, you can install [the modified version of the PSM apk](https://silica.codes/Li/NoPssDrm/src/branch/no-root).
Install the PlayStation Mobile App :
https://web.archive.org/web/20150311233351/http://playstation.com/psm/store/en.html, if you do not already have it.
Install the NoPssDrm.apk file;
Approve all permissions and grant it root access.
then install the NoPsmDrm Android app, and click the "Install" button. grant it root permission and you should be good to go!
- If your device is not PlayStation Certified, you will have to "Certify" it first,
the NoPssDrm app itself can do this, just press the "PS Certify" button.
Put NoPsmDrm backups of games into /sdcard/data/android/com.playstation.psstore/files/psm ...
- If you do not have the PlayStation Mobile app installed, you will see a "Install PSM" button.
this will download the PSM.apk from psmreborn.com, and then install it onto your phone.
(this automatically does the android 14+ ``--bypass-low-target-sdk-block`` if needed.)
- Once both PSM and the PlayStation Certificates are installed, press the "Install NoPsmDrm" button.
this will install the actual NoPsmDrm patches to the app, and allow PSM games to be played with it.
You can then just place NoPsmDrm backups of games into /sdcard/data/android/com.playstation.psstore/files/psm ...
the format Vita NoPsmDrm backups come in usually contains an RW/ and RO/ folder,
which isn't present on the Android version. you can just move all the files from RO and RW
into the games Title ID folder (the NPXAXXXX one..), and that should get it working
## "PlayStation Suite" / PSP & PS1 Games
When starting one of these games you'll be given the option to launch either with ``PlayStation Mobile`` or ``NoPs1Drm``
you just need to select the ``NoPs1Drm`` option, both times, and the game should launch assuming you have the correct matching APK & ZPAK pair
for the game, and the game can actually run on your device.
-- known issues:
- Games only run with wifi off .. (i think its trying to check for updates or something..)
- 8008103F error code when starting -- on some devices, wifi is required to be turned on when starting the app for the first time.
this is not actually accessing a server and its just so it can read your Mac Address, which PSM needs for (something???)
## Known Issues:
- ~~Games only run with wifi off .. (i think its trying to check for updates or something..)~~ (fixed with the Xposed module)
- ~~8008103F error code when starting -- on some devices, wifi is required to be turned on when starting the app for the first time.
this is not actually accessing a server and its just so it can read your Mac Address, which PSM needs for (something???)~~ (fixed with the Xposed module)
-- source code?
## What patches there are // what they do
### /system files (or the magisk module on android 6+)
Marks your device as "Playstation Certified", allowing the Playstation Mobile application to run.
### Patches to the shared_prefs files (SigninInfo.xml , com.playstation.psstore_preferences.xml)
Gets PSM to think that you've already logged in, as well as getting it to not check for updates.
### The libdefault.so mod
Does most of the work on the PSM side, allowing the games to run and things like that.
### The Xposed module
Patches a couple things, networking checks, and PS1 certification checks.
## source code? // external libraries
libdefault.so mod in here is https://silica.codes/Li/libdefault_proxy
libpsmkdc_jni mod is https://silica.codes/Li/libpsmkdc_stub
the library.db has had the following trigger added :
```
CREATE TRIGGER CONTENT_ID_MEMES AFTER INSERT ON LibraryTable
BEGIN
UPDATE LibraryTable SET content_id="UM0105-" || title_id || "_00-0000000000000000" WHERE title_id = new.title_id;
END;
```
... the rest should be in the installer apk code so :d
``com.playstation.playstationcertified.jar``
is taken from an xperia play, however its an empty JAR file with only a class constructor in it and nothing else.
NP Ticket generation is done via a library created by olebeck; see https://github.com/olebeck/npticketjava
-- Permissions explaination
## Permissions explaination
SuperUser - This app works by modifying the internal data for the PSM application (at /data/data/com.playstation.psstore) so it sees it as if you have already logged into the app and setup an account, then it patches libdefault and libpsmkdc for nopsmdrm-like patches,
@ -49,12 +73,13 @@ Phone calls - This is litterally, just to read your IMEI number, you see PsmDrm
com.playstation.psscertified - this is a specical permission given to be able to access the pscertified framework, which is used to check if your device is "PlayStation Certified".
-- Credits
## Credits
- frangarj for the original NoPsmDrm on PSVita https://github.com/frangarcj/NoPsmDrm/
- Chaser - an absolute legend who still had their old XPLAY with PSM running on it *still going* all these years later, could never have done it without ya!
- random(), helping us work out what was wrong on Android 5+
- frangarj, for the original NoPsmDrm on PSVita https://github.com/frangarcj/NoPsmDrm/
- Chaser, an absolute legend who still had their old XPLAY with PSM running on it *still going* all these years later, could never have done it without ya!
- random(), helping us work out what was wrong on Android 5+ (and plenty of editing to this readme.md)
- rosstonovsky, this random library for reading android's binary XML files; https://github.com/rosstonovsky/ABXUtils/tree/master/abxutils
- Li, for being the single person who has done the most research into PSM out of anyone ever ..
- ele7enxxh, for the hooking library that actually works on android 2.2.X https://github.com/ele7enxxh/Android-Inline-Hook/tree/master
- olebeck, for their knowledge of NP Tickets, and how to generate them https://github.com/olebeck/npticketjava
- Whomever was around before me, Thanks for keeping the dream alive..
- ele7enxxh for the hooking library that actually works on android 2.2.X https://github.com/ele7enxxh/Android-Inline-Hook/tree/master

View File

@ -10,11 +10,17 @@ dependencyResolutionManagement {
repositories {
google()
mavenCentral()
maven { url 'https://jitpack.io' }
jcenter()
maven {
name = "olebeck-silica.codes"
url = uri("https://silica.codes/api/packages/olebeck/maven")
}
maven {
url 'https://jitpack.io'
}
}
}
rootProject.name = "nopsmdrm"
rootProject.name = "nopssdrm"
include ':app'
include ':libsuperuser'
include ':libABX'
//include ':libNpTicket'