Repository: ChendoChap/Playstation-4-Save-Mounter Branch: master Commit: d1369b76789b Files: 18 Total size: 129.3 KB Directory structure: gitextract_y_dojabp/ ├── .gitignore ├── LICENSE ├── Main.Designer.cs ├── Main.cs ├── PS4Saves.csproj ├── Program.cs ├── Properties/ │ └── AssemblyInfo.cs ├── README.md ├── functions.cs ├── libdebug/ │ ├── PS4DBG.Console.cs │ ├── PS4DBG.Debug.cs │ ├── PS4DBG.Kernel.cs │ ├── PS4DBG.Proc.cs │ ├── PS4DBG.cs │ ├── Process.cs │ └── Registers.cs ├── offsets.cs └── structs.cs ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. ## ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore # User-specific files *.suo *.user *.userosscache *.sln.docstates # User-specific files (MonoDevelop/Xamarin Studio) *.userprefs # Build results [Dd]ebug/ [Dd]ebugPublic/ [Rr]elease/ [Rr]eleases/ x64/ x86/ bld/ [Bb]in/ [Oo]bj/ [Ll]og/ # Visual Studio 2015/2017 cache/options directory .vs/ # Uncomment if you have tasks that create the project's static files in wwwroot #wwwroot/ # Visual Studio 2017 auto generated files Generated\ Files/ # MSTest test Results [Tt]est[Rr]esult*/ [Bb]uild[Ll]og.* # NUNIT *.VisualState.xml TestResult.xml # Build Results of an ATL Project [Dd]ebugPS/ [Rr]eleasePS/ dlldata.c # Benchmark Results BenchmarkDotNet.Artifacts/ # .NET Core project.lock.json project.fragment.lock.json artifacts/ **/Properties/launchSettings.json # StyleCop StyleCopReport.xml # Files built by Visual Studio *_i.c *_p.c *_i.h *.ilk *.meta *.obj *.iobj *.pch *.pdb *.ipdb *.pgc *.pgd *.rsp *.sbr *.tlb *.tli *.tlh *.tmp *.tmp_proj *.log *.vspscc *.vssscc .builds *.pidb *.svclog *.scc # Chutzpah Test files _Chutzpah* # Visual C++ cache files ipch/ *.aps *.ncb *.opendb *.opensdf *.sdf *.cachefile *.VC.db *.VC.VC.opendb # Visual Studio profiler *.psess *.vsp *.vspx *.sap # Visual Studio Trace Files *.e2e # TFS 2012 Local Workspace $tf/ # Guidance Automation Toolkit *.gpState # ReSharper is a .NET coding add-in _ReSharper*/ *.[Rr]e[Ss]harper *.DotSettings.user # JustCode is a .NET coding add-in .JustCode # TeamCity is a build add-in _TeamCity* # DotCover is a Code Coverage Tool *.dotCover # AxoCover is a Code Coverage Tool .axoCover/* !.axoCover/settings.json # Visual Studio code coverage results *.coverage *.coveragexml # NCrunch _NCrunch_* .*crunch*.local.xml nCrunchTemp_* # MightyMoose *.mm.* AutoTest.Net/ # Web workbench (sass) .sass-cache/ # Installshield output folder [Ee]xpress/ # DocProject is a documentation generator add-in DocProject/buildhelp/ DocProject/Help/*.HxT DocProject/Help/*.HxC DocProject/Help/*.hhc DocProject/Help/*.hhk DocProject/Help/*.hhp DocProject/Help/Html2 DocProject/Help/html # Click-Once directory publish/ # Publish Web Output *.[Pp]ublish.xml *.azurePubxml # Note: Comment the next line if you want to checkin your web deploy settings, # but database connection strings (with potential passwords) will be unencrypted *.pubxml *.publishproj # Microsoft Azure Web App publish settings. Comment the next line if you want to # checkin your Azure Web App publish settings, but sensitive information contained # in these scripts will be unencrypted PublishScripts/ # NuGet Packages *.nupkg # The packages folder can be ignored because of Package Restore **/[Pp]ackages/* # except build/, which is used as an MSBuild target. !**/[Pp]ackages/build/ # Uncomment if necessary however generally it will be regenerated when needed #!**/[Pp]ackages/repositories.config # NuGet v3's project.json files produces more ignorable files *.nuget.props *.nuget.targets # Microsoft Azure Build Output csx/ *.build.csdef # Microsoft Azure Emulator ecf/ rcf/ # Windows Store app package directories and files AppPackages/ BundleArtifacts/ Package.StoreAssociation.xml _pkginfo.txt *.appx # Visual Studio cache files # files ending in .cache can be ignored *.[Cc]ache # but keep track of directories ending in .cache !*.[Cc]ache/ # Others ClientBin/ ~$* *~ *.dbmdl *.dbproj.schemaview *.jfm *.pfx *.publishsettings orleans.codegen.cs # Including strong name files can present a security risk # (https://github.com/github/gitignore/pull/2483#issue-259490424) #*.snk # Since there are multiple workflows, uncomment next line to ignore bower_components # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) #bower_components/ # RIA/Silverlight projects Generated_Code/ # Backup & report files from converting an old project file # to a newer Visual Studio version. Backup files are not needed, # because we have git ;-) _UpgradeReport_Files/ Backup*/ UpgradeLog*.XML UpgradeLog*.htm ServiceFabricBackup/ *.rptproj.bak # SQL Server files *.mdf *.ldf *.ndf # Business Intelligence projects *.rdl.data *.bim.layout *.bim_*.settings *.rptproj.rsuser # Microsoft Fakes FakesAssemblies/ # GhostDoc plugin setting file *.GhostDoc.xml # Node.js Tools for Visual Studio .ntvs_analysis.dat node_modules/ # Visual Studio 6 build log *.plg # Visual Studio 6 workspace options file *.opt # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) *.vbw # Visual Studio LightSwitch build output **/*.HTMLClient/GeneratedArtifacts **/*.DesktopClient/GeneratedArtifacts **/*.DesktopClient/ModelManifest.xml **/*.Server/GeneratedArtifacts **/*.Server/ModelManifest.xml _Pvt_Extensions # Paket dependency manager .paket/paket.exe paket-files/ # FAKE - F# Make .fake/ # JetBrains Rider .idea/ *.sln.iml # CodeRush .cr/ # Python Tools for Visual Studio (PTVS) __pycache__/ *.pyc # Cake - Uncomment if you are using it # tools/** # !tools/packages.config # Tabs Studio *.tss # Telerik's JustMock configuration file *.jmconfig # BizTalk build output *.btp.cs *.btm.cs *.odx.cs *.xsd.cs # OpenCover UI analysis results OpenCover/ # Azure Stream Analytics local run output ASALocalRun/ # MSBuild Binary and Structured Log *.binlog # NVidia Nsight GPU debugger configuration file *.nvuser # MFractors (Xamarin productivity tool) working folder .mfractor/ ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2018 ChendoChap Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: Main.Designer.cs ================================================ namespace PS4Saves { partial class Main { /// /// Required designer variable. /// private System.ComponentModel.IContainer components = null; /// /// Clean up any resources being used. /// /// true if managed resources should be disposed; otherwise, false. protected override void Dispose(bool disposing) { if (disposing && (components != null)) { components.Dispose(); } base.Dispose(disposing); } #region Windows Form Designer generated code /// /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// private void InitializeComponent() { this.components = new System.ComponentModel.Container(); this.ipTextBox = new System.Windows.Forms.TextBox(); this.connectButton = new System.Windows.Forms.Button(); this.setupButton = new System.Windows.Forms.Button(); this.userComboBox = new System.Windows.Forms.ComboBox(); this.dirsComboBox = new System.Windows.Forms.ComboBox(); this.searchButton = new System.Windows.Forms.Button(); this.mountButton = new System.Windows.Forms.Button(); this.unmountButton = new System.Windows.Forms.Button(); this.connectionGroupBox = new System.Windows.Forms.GroupBox(); this.getGamesButton = new System.Windows.Forms.Button(); this.gamesComboBox = new System.Windows.Forms.ComboBox(); this.payloadButton = new System.Windows.Forms.Button(); this.ipLabel = new System.Windows.Forms.Label(); this.createGroupBox = new System.Windows.Forms.GroupBox(); this.sizeLabel = new System.Windows.Forms.Label(); this.sizeTrackBar = new System.Windows.Forms.TrackBar(); this.nameLabel = new System.Windows.Forms.Label(); this.nameTextBox = new System.Windows.Forms.TextBox(); this.createButton = new System.Windows.Forms.Button(); this.mountGroupBox = new System.Windows.Forms.GroupBox(); this.infoGroupBox = new System.Windows.Forms.GroupBox(); this.dateTextBox = new System.Windows.Forms.TextBox(); this.dateLabel = new System.Windows.Forms.Label(); this.detailsTextBox = new System.Windows.Forms.TextBox(); this.detailsLabel = new System.Windows.Forms.Label(); this.subtitleTextBox = new System.Windows.Forms.TextBox(); this.subtitleLabel = new System.Windows.Forms.Label(); this.titleTextBox = new System.Windows.Forms.TextBox(); this.titleLabel = new System.Windows.Forms.Label(); this.sizeToolTip = new System.Windows.Forms.ToolTip(this.components); this.statusLabel = new System.Windows.Forms.Label(); this.connectionGroupBox.SuspendLayout(); this.createGroupBox.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.sizeTrackBar)).BeginInit(); this.mountGroupBox.SuspendLayout(); this.infoGroupBox.SuspendLayout(); this.SuspendLayout(); // // ipTextBox // this.ipTextBox.Location = new System.Drawing.Point(70, 19); this.ipTextBox.Name = "ipTextBox"; this.ipTextBox.Size = new System.Drawing.Size(117, 20); this.ipTextBox.TabIndex = 0; // // connectButton // this.connectButton.Location = new System.Drawing.Point(284, 19); this.connectButton.Name = "connectButton"; this.connectButton.Size = new System.Drawing.Size(90, 20); this.connectButton.TabIndex = 2; this.connectButton.Text = "Connect"; this.connectButton.UseVisualStyleBackColor = true; this.connectButton.Click += new System.EventHandler(this.connectButton_Click); // // setupButton // this.setupButton.Location = new System.Drawing.Point(7, 45); this.setupButton.Name = "setupButton"; this.setupButton.Size = new System.Drawing.Size(181, 21); this.setupButton.TabIndex = 3; this.setupButton.Text = "Setup"; this.setupButton.UseVisualStyleBackColor = true; this.setupButton.Click += new System.EventHandler(this.setupButton_Click); // // userComboBox // this.userComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; this.userComboBox.FormattingEnabled = true; this.userComboBox.Location = new System.Drawing.Point(193, 45); this.userComboBox.Name = "userComboBox"; this.userComboBox.Size = new System.Drawing.Size(181, 21); this.userComboBox.TabIndex = 4; this.userComboBox.SelectedIndexChanged += new System.EventHandler(this.userComboBox_SelectedIndexChanged); // // dirsComboBox // this.dirsComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; this.dirsComboBox.FormattingEnabled = true; this.dirsComboBox.Location = new System.Drawing.Point(193, 19); this.dirsComboBox.Name = "dirsComboBox"; this.dirsComboBox.Size = new System.Drawing.Size(180, 21); this.dirsComboBox.TabIndex = 1; this.dirsComboBox.SelectedIndexChanged += new System.EventHandler(this.dirsComboBox_SelectedIndexChanged); // // searchButton // this.searchButton.Location = new System.Drawing.Point(6, 19); this.searchButton.Name = "searchButton"; this.searchButton.Size = new System.Drawing.Size(181, 21); this.searchButton.TabIndex = 0; this.searchButton.Text = "Search"; this.searchButton.UseVisualStyleBackColor = true; this.searchButton.Click += new System.EventHandler(this.searchButton_Click); // // mountButton // this.mountButton.Location = new System.Drawing.Point(6, 48); this.mountButton.Name = "mountButton"; this.mountButton.Size = new System.Drawing.Size(181, 23); this.mountButton.TabIndex = 2; this.mountButton.Text = "Mount"; this.mountButton.UseVisualStyleBackColor = true; this.mountButton.Click += new System.EventHandler(this.mountButton_Click); // // unmountButton // this.unmountButton.Location = new System.Drawing.Point(192, 48); this.unmountButton.Name = "unmountButton"; this.unmountButton.Size = new System.Drawing.Size(181, 23); this.unmountButton.TabIndex = 3; this.unmountButton.Text = "Unmount"; this.unmountButton.UseVisualStyleBackColor = true; this.unmountButton.Click += new System.EventHandler(this.unmountButton_Click); // // connectionGroupBox // this.connectionGroupBox.Controls.Add(this.getGamesButton); this.connectionGroupBox.Controls.Add(this.gamesComboBox); this.connectionGroupBox.Controls.Add(this.payloadButton); this.connectionGroupBox.Controls.Add(this.ipLabel); this.connectionGroupBox.Controls.Add(this.ipTextBox); this.connectionGroupBox.Controls.Add(this.connectButton); this.connectionGroupBox.Controls.Add(this.setupButton); this.connectionGroupBox.Controls.Add(this.userComboBox); this.connectionGroupBox.Location = new System.Drawing.Point(7, 12); this.connectionGroupBox.Name = "connectionGroupBox"; this.connectionGroupBox.Size = new System.Drawing.Size(379, 105); this.connectionGroupBox.TabIndex = 0; this.connectionGroupBox.TabStop = false; this.connectionGroupBox.Text = "Connection"; // // getGamesButton // this.getGamesButton.Location = new System.Drawing.Point(6, 72); this.getGamesButton.Name = "getGamesButton"; this.getGamesButton.Size = new System.Drawing.Size(181, 21); this.getGamesButton.TabIndex = 5; this.getGamesButton.Text = "Get Games"; this.getGamesButton.UseVisualStyleBackColor = true; this.getGamesButton.Click += new System.EventHandler(this.getGamesButton_Click); // // gamesComboBox // this.gamesComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; this.gamesComboBox.FormattingEnabled = true; this.gamesComboBox.Location = new System.Drawing.Point(192, 72); this.gamesComboBox.Name = "gamesComboBox"; this.gamesComboBox.Size = new System.Drawing.Size(181, 21); this.gamesComboBox.TabIndex = 6; this.gamesComboBox.SelectedIndexChanged += new System.EventHandler(this.gamesComboBox_SelectedIndexChanged); // // payloadButton // this.payloadButton.Location = new System.Drawing.Point(192, 19); this.payloadButton.Name = "payloadButton"; this.payloadButton.Size = new System.Drawing.Size(90, 20); this.payloadButton.TabIndex = 1; this.payloadButton.Text = "Send Payload"; this.payloadButton.UseVisualStyleBackColor = true; this.payloadButton.Click += new System.EventHandler(this.payloadButton_Click); // // ipLabel // this.ipLabel.AutoSize = true; this.ipLabel.Location = new System.Drawing.Point(6, 22); this.ipLabel.Name = "ipLabel"; this.ipLabel.Size = new System.Drawing.Size(58, 13); this.ipLabel.TabIndex = 6; this.ipLabel.Text = "ip address:"; // // createGroupBox // this.createGroupBox.Controls.Add(this.sizeLabel); this.createGroupBox.Controls.Add(this.sizeTrackBar); this.createGroupBox.Controls.Add(this.nameLabel); this.createGroupBox.Controls.Add(this.nameTextBox); this.createGroupBox.Controls.Add(this.createButton); this.createGroupBox.Location = new System.Drawing.Point(7, 210); this.createGroupBox.Name = "createGroupBox"; this.createGroupBox.Size = new System.Drawing.Size(379, 129); this.createGroupBox.TabIndex = 2; this.createGroupBox.TabStop = false; this.createGroupBox.Text = "Create New Saves"; // // sizeLabel // this.sizeLabel.AutoSize = true; this.sizeLabel.Location = new System.Drawing.Point(6, 48); this.sizeLabel.Name = "sizeLabel"; this.sizeLabel.Size = new System.Drawing.Size(76, 13); this.sizeLabel.TabIndex = 9; this.sizeLabel.Text = "max save size:"; // // sizeTrackBar // this.sizeTrackBar.Location = new System.Drawing.Point(117, 48); this.sizeTrackBar.Maximum = 32768; this.sizeTrackBar.Minimum = 96; this.sizeTrackBar.Name = "sizeTrackBar"; this.sizeTrackBar.Size = new System.Drawing.Size(257, 45); this.sizeTrackBar.TabIndex = 1; this.sizeTrackBar.Value = 96; this.sizeTrackBar.Scroll += new System.EventHandler(this.sizeTrackBar_Scroll); // // nameLabel // this.nameLabel.AutoSize = true; this.nameLabel.Location = new System.Drawing.Point(6, 25); this.nameLabel.Name = "nameLabel"; this.nameLabel.Size = new System.Drawing.Size(105, 13); this.nameLabel.TabIndex = 7; this.nameLabel.Text = "save directory name:"; // // nameTextBox // this.nameTextBox.Location = new System.Drawing.Point(117, 22); this.nameTextBox.MaxLength = 31; this.nameTextBox.Name = "nameTextBox"; this.nameTextBox.Size = new System.Drawing.Size(256, 20); this.nameTextBox.TabIndex = 0; // // createButton // this.createButton.Location = new System.Drawing.Point(5, 99); this.createButton.Name = "createButton"; this.createButton.Size = new System.Drawing.Size(367, 23); this.createButton.TabIndex = 2; this.createButton.Text = "Create Save"; this.createButton.UseVisualStyleBackColor = true; this.createButton.Click += new System.EventHandler(this.createButton_Click); // // mountGroupBox // this.mountGroupBox.Controls.Add(this.searchButton); this.mountGroupBox.Controls.Add(this.dirsComboBox); this.mountGroupBox.Controls.Add(this.mountButton); this.mountGroupBox.Controls.Add(this.unmountButton); this.mountGroupBox.Location = new System.Drawing.Point(7, 123); this.mountGroupBox.Name = "mountGroupBox"; this.mountGroupBox.Size = new System.Drawing.Size(379, 81); this.mountGroupBox.TabIndex = 1; this.mountGroupBox.TabStop = false; this.mountGroupBox.Text = "Mount Existing Saves"; // // infoGroupBox // this.infoGroupBox.Controls.Add(this.dateTextBox); this.infoGroupBox.Controls.Add(this.dateLabel); this.infoGroupBox.Controls.Add(this.detailsTextBox); this.infoGroupBox.Controls.Add(this.detailsLabel); this.infoGroupBox.Controls.Add(this.subtitleTextBox); this.infoGroupBox.Controls.Add(this.subtitleLabel); this.infoGroupBox.Controls.Add(this.titleTextBox); this.infoGroupBox.Controls.Add(this.titleLabel); this.infoGroupBox.Location = new System.Drawing.Point(392, 12); this.infoGroupBox.Name = "infoGroupBox"; this.infoGroupBox.Size = new System.Drawing.Size(396, 327); this.infoGroupBox.TabIndex = 3; this.infoGroupBox.TabStop = false; this.infoGroupBox.Text = "Save Info"; // // dateTextBox // this.dateTextBox.Location = new System.Drawing.Point(9, 294); this.dateTextBox.Name = "dateTextBox"; this.dateTextBox.ReadOnly = true; this.dateTextBox.Size = new System.Drawing.Size(381, 20); this.dateTextBox.TabIndex = 3; // // dateLabel // this.dateLabel.AutoSize = true; this.dateLabel.Location = new System.Drawing.Point(6, 278); this.dateLabel.Name = "dateLabel"; this.dateLabel.Size = new System.Drawing.Size(31, 13); this.dateLabel.TabIndex = 6; this.dateLabel.Text = "date:"; // // detailsTextBox // this.detailsTextBox.Location = new System.Drawing.Point(9, 166); this.detailsTextBox.Multiline = true; this.detailsTextBox.Name = "detailsTextBox"; this.detailsTextBox.ReadOnly = true; this.detailsTextBox.Size = new System.Drawing.Size(381, 109); this.detailsTextBox.TabIndex = 2; // // detailsLabel // this.detailsLabel.AutoSize = true; this.detailsLabel.Location = new System.Drawing.Point(6, 150); this.detailsLabel.Name = "detailsLabel"; this.detailsLabel.Size = new System.Drawing.Size(40, 13); this.detailsLabel.TabIndex = 4; this.detailsLabel.Text = "details:"; // // subtitleTextBox // this.subtitleTextBox.Location = new System.Drawing.Point(9, 101); this.subtitleTextBox.Multiline = true; this.subtitleTextBox.Name = "subtitleTextBox"; this.subtitleTextBox.ReadOnly = true; this.subtitleTextBox.Size = new System.Drawing.Size(381, 46); this.subtitleTextBox.TabIndex = 1; // // subtitleLabel // this.subtitleLabel.AutoSize = true; this.subtitleLabel.Location = new System.Drawing.Point(6, 85); this.subtitleLabel.Name = "subtitleLabel"; this.subtitleLabel.Size = new System.Drawing.Size(43, 13); this.subtitleLabel.TabIndex = 2; this.subtitleLabel.Text = "subtitle:"; // // titleTextBox // this.titleTextBox.Location = new System.Drawing.Point(9, 35); this.titleTextBox.Multiline = true; this.titleTextBox.Name = "titleTextBox"; this.titleTextBox.ReadOnly = true; this.titleTextBox.Size = new System.Drawing.Size(381, 47); this.titleTextBox.TabIndex = 0; // // titleLabel // this.titleLabel.AutoSize = true; this.titleLabel.Location = new System.Drawing.Point(6, 19); this.titleLabel.Name = "titleLabel"; this.titleLabel.Size = new System.Drawing.Size(26, 13); this.titleLabel.TabIndex = 0; this.titleLabel.Text = "title:"; // // statusLabel // this.statusLabel.AutoSize = true; this.statusLabel.Location = new System.Drawing.Point(4, 342); this.statusLabel.Name = "statusLabel"; this.statusLabel.Size = new System.Drawing.Size(40, 13); this.statusLabel.TabIndex = 13; this.statusLabel.Text = "Status:"; // // Main // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(797, 362); this.Controls.Add(this.statusLabel); this.Controls.Add(this.infoGroupBox); this.Controls.Add(this.mountGroupBox); this.Controls.Add(this.createGroupBox); this.Controls.Add(this.connectionGroupBox); this.Name = "Main"; this.Text = "Playstation 4 Save Mounter 1.5 [ps4debug]"; this.connectionGroupBox.ResumeLayout(false); this.connectionGroupBox.PerformLayout(); this.createGroupBox.ResumeLayout(false); this.createGroupBox.PerformLayout(); ((System.ComponentModel.ISupportInitialize)(this.sizeTrackBar)).EndInit(); this.mountGroupBox.ResumeLayout(false); this.infoGroupBox.ResumeLayout(false); this.infoGroupBox.PerformLayout(); this.ResumeLayout(false); this.PerformLayout(); } #endregion private System.Windows.Forms.TextBox ipTextBox; private System.Windows.Forms.Button connectButton; private System.Windows.Forms.Button setupButton; private System.Windows.Forms.ComboBox userComboBox; private System.Windows.Forms.ComboBox dirsComboBox; private System.Windows.Forms.Button searchButton; private System.Windows.Forms.Button mountButton; private System.Windows.Forms.Button unmountButton; private System.Windows.Forms.GroupBox connectionGroupBox; private System.Windows.Forms.Label ipLabel; private System.Windows.Forms.GroupBox createGroupBox; private System.Windows.Forms.TextBox nameTextBox; private System.Windows.Forms.Button createButton; private System.Windows.Forms.GroupBox mountGroupBox; private System.Windows.Forms.GroupBox infoGroupBox; private System.Windows.Forms.Label nameLabel; private System.Windows.Forms.TrackBar sizeTrackBar; private System.Windows.Forms.Label sizeLabel; private System.Windows.Forms.ToolTip sizeToolTip; private System.Windows.Forms.Label statusLabel; private System.Windows.Forms.TextBox dateTextBox; private System.Windows.Forms.Label dateLabel; private System.Windows.Forms.TextBox detailsTextBox; private System.Windows.Forms.Label detailsLabel; private System.Windows.Forms.TextBox subtitleTextBox; private System.Windows.Forms.Label subtitleLabel; private System.Windows.Forms.TextBox titleTextBox; private System.Windows.Forms.Label titleLabel; private System.Windows.Forms.Button payloadButton; private System.Windows.Forms.Button getGamesButton; private System.Windows.Forms.ComboBox gamesComboBox; } } ================================================ FILE: Main.cs ================================================ using libdebug; using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Net; using System.Net.Sockets; using System.Runtime.InteropServices; using System.Threading; using System.Windows.Forms; namespace PS4Saves { public partial class Main : Form { PS4DBG ps4 = new PS4DBG(); private int pid; private ulong stub; private ulong libSceUserServiceBase = 0x0; private ulong libSceSaveDataBase = 0x0; private ulong executableBase = 0x0; private ulong libSceLibcInternalBase = 0x0; private ulong GetSaveDirectoriesAddr = 0; private ulong GetUsersAddr = 0; private int user = 0x0; private string selectedGame = null; string mp = ""; bool log = false; public Main() { InitializeComponent(); string[] args = Environment.GetCommandLineArgs(); if (args.Length == 2 && args[1] == "-log") { log = true; } if (File.Exists("ip")) { ipTextBox.Text = File.ReadAllText("ip"); } } public static string FormatSize(double size) { const long BytesInKilobytes = 1024; const long BytesInMegabytes = BytesInKilobytes * 1024; const long BytesInGigabytes = BytesInMegabytes * 1024; double value; string str; if (size < BytesInGigabytes) { value = size / BytesInMegabytes; str = "MB"; } else { value = size /BytesInGigabytes; str = "GB"; } return String.Format("{0:0.##} {1}", value, str); } private void sizeTrackBar_Scroll(object sender, EventArgs e) { sizeToolTip.SetToolTip(sizeTrackBar, FormatSize((double)(sizeTrackBar.Value * 32768))); } private void SetStatus(string msg) { statusLabel.Text = $"Status: {msg}"; } private void WriteLog(string msg) { if(log) { msg = $"|{msg}|"; var a = msg.Length / 2; for (var i = 0; i < 48 - a; i++) { msg = msg.Insert(0, " "); } for (var i = msg.Length; i < 96; i++) { msg += " "; } var dateAndTime = DateTime.Now; var logStr = $"|{dateAndTime:MM/dd/yyyy} {dateAndTime:hh:mm:ss tt}| |{msg}|"; if (File.Exists(@"log.txt")) { File.AppendAllText(@"log.txt", $"{logStr}{Environment.NewLine}"); } else { using (var sw = File.CreateText(@"log.txt")) { sw.WriteLine(logStr); } } Console.WriteLine(logStr); } } private void connectButton_Click(object sender, EventArgs e) { try { if (!checkIP(ipTextBox.Text)) { SetStatus("Invalid IP"); return; } ps4 = new PS4DBG(ipTextBox.Text); ps4.Connect(); if (!ps4.IsConnected) { throw new Exception(); } SetStatus("Connected"); if (!File.Exists("ip")) { File.WriteAllText("ip", ipTextBox.Text); } else { using (var sw = File.CreateText(@"log.txt")) { sw.Write(ipTextBox.Text); } } } catch { SetStatus("Failed To Connect"); } } private void setupButton_Click(object sender, EventArgs e) { if (!ps4.IsConnected) { SetStatus("Not connected to ps4"); return; } var pl = ps4.GetProcessList(); var su = pl.FindProcess("SceShellUI"); if (su == null) { SetStatus("Couldn't find SceShellUI"); return; } pid = su.pid; var pm = ps4.GetProcessMaps(pid); var tmp = pm.FindEntry("libSceSaveData.sprx")?.start; if (tmp == null) { MessageBox.Show("savedata lib not found", "Error"); return; } libSceSaveDataBase = (ulong)tmp; tmp = pm.FindEntry("libSceUserService.sprx")?.start; if (tmp == null) { MessageBox.Show("user service lib not found", "Error"); return; } libSceUserServiceBase = (ulong)tmp; tmp = pm.FindEntry("executable")?.start; if (tmp == null) { MessageBox.Show("executable not found", "Error"); return; } executableBase = (ulong)tmp; tmp = pm.FindEntry("libSceLibcInternal.sprx")?.start; if (tmp == null) { MessageBox.Show("libc not found", "Error"); return; } libSceLibcInternalBase = (ulong)tmp; stub = pm.FindEntry("(NoName)clienthandler") == null ? ps4.InstallRPC(pid) : pm.FindEntry("(NoName)clienthandler").start; var ret = ps4.Call(pid, stub, libSceSaveDataBase + offsets.sceSaveDataInitialize3); WriteLog($"sceSaveDataInitialize3 ret = 0x{ret:X}"); //PATCHES //SAVEDATA LIBRARY PATCHES ps4.WriteMemory(pid, libSceSaveDataBase + 0x32998, (byte)0x00); // 'sce_' patch ps4.WriteMemory(pid, libSceSaveDataBase + 0x31699, (byte)0x00); // 'sce_sdmemory' patch ps4.WriteMemory(pid, libSceSaveDataBase + 0x01119, (byte)0x30); // '_' patch var l = ps4.GetProcessList(); var s = l.FindProcess("SceShellCore"); var m = ps4.GetProcessMaps(s.pid); var ex = m.FindEntry("executable"); //SHELLCORE PATCHES ps4.WriteMemory(s.pid, ex.start + 0xD42843, (byte)0x00); // 'sce_sdmemory' patch ps4.WriteMemory(s.pid, ex.start + 0x7E4DC0, new byte[]{0x48, 0x31, 0xC0, 0xC3}); //verify keystone patch ps4.WriteMemory(s.pid, ex.start + 0x68BA0, new byte[] {0x31, 0xC0, 0xC3}); //transfer mount permission patch eg mount foreign saves with write permission ps4.WriteMemory(s.pid, ex.start + 0xC54F0, new byte[] { 0x31, 0xC0, 0xC3 });//patch psn check to load saves saves foreign to current account ps4.WriteMemory(s.pid, ex.start + 0x6A349, new byte[] { 0x90, 0x90 }); // ^ ps4.WriteMemory(s.pid, ex.start + 0x686AE, new byte[] {0x90, 0x90, 0x90, 0x90, 0x90, 0x90}); // something something patches... ps4.WriteMemory(s.pid, ex.start + 0x67FCA, new byte[] { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); // don't even remember doing this ps4.WriteMemory(s.pid, ex.start + 0x67798, new byte[] { 0x90, 0x90}); //nevah jump ps4.WriteMemory(s.pid, ex.start + 0x679D5, new byte[] { 0x90, 0xE9 }); //always jump //WRITE CUSTOM FUNCTIONS GetSaveDirectoriesAddr = ps4.AllocateMemory(pid, 0x8000); ps4.WriteMemory(pid, GetSaveDirectoriesAddr, functions.GetSaveDirectories); ps4.WriteMemory(pid, GetSaveDirectoriesAddr + 0x12, executableBase + 0x81E800); //opendir ps4.WriteMemory(pid, GetSaveDirectoriesAddr + 0x20, executableBase + 0x81E810); //readdir ps4.WriteMemory(pid, GetSaveDirectoriesAddr + 0x2E, executableBase + 0x81E7F0);//closedir ps4.WriteMemory(pid, GetSaveDirectoriesAddr + 0x3C, libSceLibcInternalBase + 0x8B1A0); //strcpy GetUsersAddr = GetSaveDirectoriesAddr + (uint)functions.GetSaveDirectories.Length + 0x20; ps4.WriteMemory(pid, GetUsersAddr, functions.GetUsers); ps4.WriteMemory(pid, GetUsersAddr + 0x15, libSceUserServiceBase + offsets.sceUserServiceGetLoginUserIdList); ps4.WriteMemory(pid, GetUsersAddr + 0x23, libSceUserServiceBase + offsets.sceUserServiceGetUserName); ps4.WriteMemory(pid, GetUsersAddr + 0x31, libSceLibcInternalBase + 0x8B1A0); //strcpy var users = GetUsers(); userComboBox.DataSource = users; SetStatus("Setup Done :)"); } private void searchButton_Click(object sender, EventArgs e) { if (!ps4.IsConnected) { SetStatus("Not connected to ps4"); return; } if (pid == 0) { SetStatus("dont forget to click setup"); return; } if (selectedGame == null) { SetStatus("No game selected"); return; } var pm = ps4.GetProcessMaps(pid); if (pm.FindEntry("(NoName)clienthandler") == null) { SetStatus("RPC Stub Not Found"); return; } var dirNameAddr = ps4.AllocateMemory(pid, Marshal.SizeOf(typeof(SceSaveDataDirName)) * 1024 + 0x10 + Marshal.SizeOf(typeof(SceSaveDataParam)) * 1024); var titleIdAddr = dirNameAddr + (uint) Marshal.SizeOf(typeof(SceSaveDataDirName)) * 1024; var paramAddr = titleIdAddr + 0x10; SceSaveDataDirNameSearchCond searchCond = new SceSaveDataDirNameSearchCond { userId = GetUser(), titleId = titleIdAddr }; SceSaveDataDirNameSearchResult searchResult = new SceSaveDataDirNameSearchResult { dirNames = dirNameAddr, dirNamesNum = 1024, param = paramAddr, }; ps4.WriteMemory(pid, titleIdAddr, selectedGame); dirsComboBox.DataSource = Find(searchCond, searchResult); ps4.FreeMemory(pid, dirNameAddr, Marshal.SizeOf(typeof(SceSaveDataDirName)) * 1024 + 0x10 + Marshal.SizeOf(typeof(SceSaveDataParam)) * 1024); if (dirsComboBox.Items.Count > 0) { SetStatus($"Found {dirsComboBox.Items.Count} Save Directories :D"); } else { SetStatus("Found 0 Save Directories :("); } } private void mountButton_Click(object sender, EventArgs e) { if (!ps4.IsConnected) { SetStatus("Not connected to ps4"); return; } if (dirsComboBox.Items.Count == 0) { SetStatus("No save selected"); return; } if (selectedGame == null) { SetStatus("No game selected"); return; } var dirNameAddr = ps4.AllocateMemory(pid, Marshal.SizeOf(typeof(SceSaveDataDirName)) + 0x10 + 0x41); var titleIdAddr = dirNameAddr + (uint)Marshal.SizeOf(typeof(SceSaveDataDirName)); var fingerprintAddr = titleIdAddr + 0x10; ps4.WriteMemory(pid, titleIdAddr, selectedGame); ps4.WriteMemory(pid, fingerprintAddr, "0000000000000000000000000000000000000000000000000000000000000000"); SceSaveDataDirName dirName = new SceSaveDataDirName { data = dirsComboBox.Text }; SceSaveDataMount mount = new SceSaveDataMount { userId = GetUser(), dirName = dirNameAddr, blocks = 32768, mountMode = 0x8 | 0x2, titleId = titleIdAddr, fingerprint = fingerprintAddr }; SceSaveDataMountResult mountResult = new SceSaveDataMountResult { }; ps4.WriteMemory(pid, dirNameAddr, dirName); mp = Mount(mount, mountResult); ps4.FreeMemory(pid, dirNameAddr, Marshal.SizeOf(typeof(SceSaveDataDirName)) + 0x10 + 0x41); if (mp != "") { SetStatus($"Save Mounted in {mp}"); } else { SetStatus("Mounting Failed"); } } private void unmountButton_Click(object sender, EventArgs e) { if (!ps4.IsConnected) { SetStatus("Not connected to ps4"); return; } if (mp == "") { SetStatus("No save mounted"); return; } SceSaveDataMountPoint mountPoint = new SceSaveDataMountPoint { data = mp, }; Unmount(mountPoint); mp = null; SetStatus("Save Unmounted"); } private void createButton_Click(object sender, EventArgs e) { if (!ps4.IsConnected) { SetStatus("Not connected to ps4"); return; } if (pid == 0) { SetStatus("Don't forget to setup"); return; } if (nameTextBox.Text == "") { SetStatus("No Save Name"); return; } if (selectedGame == null) { SetStatus("No game selected"); return; } var pm = ps4.GetProcessMaps(pid); if (pm.FindEntry("(NoName)clienthandler") == null) { SetStatus("RPC Stub Not Found"); return; } var dirNameAddr = ps4.AllocateMemory(pid, Marshal.SizeOf(typeof(SceSaveDataDirName)) + 0x10 + 0x41); var titleIdAddr = dirNameAddr + (uint)Marshal.SizeOf(typeof(SceSaveDataDirName)); var fingerprintAddr = titleIdAddr + 0x10; ps4.WriteMemory(pid, fingerprintAddr, "0000000000000000000000000000000000000000000000000000000000000000"); ps4.WriteMemory(pid, titleIdAddr, selectedGame); SceSaveDataDirName dirName = new SceSaveDataDirName { data = nameTextBox.Text }; SceSaveDataMount mount = new SceSaveDataMount { userId = GetUser(), dirName = dirNameAddr, blocks = (ulong) sizeTrackBar.Value, mountMode = 4 | 2 | 8, titleId = titleIdAddr, fingerprint = fingerprintAddr }; SceSaveDataMountResult mountResult = new SceSaveDataMountResult { }; ps4.WriteMemory(pid, dirNameAddr, dirName); var mp = Mount(mount, mountResult); ps4.FreeMemory(pid, dirNameAddr, Marshal.SizeOf(typeof(SceSaveDataDirName)) + 0x10 + 0x41); if (mp != "") { SetStatus("Save Created"); SceSaveDataMountPoint mountPoint = new SceSaveDataMountPoint { data = mp, }; Unmount(mountPoint); } else { SetStatus("Save Creation Failed"); } } private int GetUser() { if(user != 0) { return user; } return InitialUser(); } private int InitialUser() { var bufferAddr = ps4.AllocateMemory(pid, sizeof(int)); ps4.Call(pid, stub, libSceUserServiceBase + offsets.sceUserServiceGetInitialUser, bufferAddr); var id = ps4.ReadMemory(pid, bufferAddr); ps4.FreeMemory(pid, bufferAddr, sizeof(int)); return id; } private SearchEntry[] Find(SceSaveDataDirNameSearchCond searchCond, SceSaveDataDirNameSearchResult searchResult) { var searchCondAddr = ps4.AllocateMemory(pid, Marshal.SizeOf(typeof(SceSaveDataDirNameSearchCond)) + Marshal.SizeOf(typeof(SceSaveDataDirNameSearchResult))); var searchResultAddr = searchCondAddr + (uint)Marshal.SizeOf(typeof(SceSaveDataDirNameSearchCond)); ps4.WriteMemory(pid, searchCondAddr, searchCond); ps4.WriteMemory(pid, searchResultAddr, searchResult); var ret = ps4.Call(pid, stub, libSceSaveDataBase + offsets.sceSaveDataDirNameSearch, searchCondAddr, searchResultAddr); WriteLog($"sceSaveDataDirNameSearch ret = 0x{ret:X}"); if ( ret == 0) { searchResult = ps4.ReadMemory(pid, searchResultAddr); SearchEntry[] sEntries = new SearchEntry[searchResult.hitNum]; var paramMemory = ps4.ReadMemory(pid, searchResult.param, (int)searchResult.hitNum * Marshal.SizeOf(typeof(SceSaveDataParam))); var dirNamesMemory = ps4.ReadMemory(pid, searchResult.dirNames, (int)searchResult.hitNum * 32); for (int i = 0; i < searchResult.hitNum; i++) { SceSaveDataParam tmp = (SceSaveDataParam)PS4DBG.GetObjectFromBytes(PS4DBG.SubArray(paramMemory, i * Marshal.SizeOf(typeof(SceSaveDataParam)), Marshal.SizeOf(typeof(SceSaveDataParam))), typeof(SceSaveDataParam)); sEntries[i] = new SearchEntry { dirName = System.Text.Encoding.UTF8.GetString(PS4DBG.SubArray(dirNamesMemory, i * 32, 32)), title = System.Text.Encoding.UTF8.GetString(tmp.title), subtitle = System.Text.Encoding.UTF8.GetString(tmp.subTitle), detail = System.Text.Encoding.UTF8.GetString(tmp.detail), time = new DateTime(1970, 1, 1).ToLocalTime().AddSeconds(tmp.mtime).ToString(), }; } ps4.FreeMemory(pid, searchCondAddr, Marshal.SizeOf(typeof(SceSaveDataDirNameSearchCond)) + Marshal.SizeOf(typeof(SceSaveDataDirNameSearchResult))); return sEntries; } ps4.FreeMemory(pid, searchCondAddr, Marshal.SizeOf(typeof(SceSaveDataDirNameSearchCond)) + Marshal.SizeOf(typeof(SceSaveDataDirNameSearchResult))); return new SearchEntry[0]; } private void Unmount(SceSaveDataMountPoint mountPoint) { var mountPointAddr = ps4.AllocateMemory(pid, Marshal.SizeOf(typeof(SceSaveDataMountPoint))); ps4.WriteMemory(pid, mountPointAddr, mountPoint); var ret = ps4.Call(pid, stub, libSceSaveDataBase + offsets.sceSaveDataUmount, mountPointAddr); WriteLog($"sceSaveDataUmount ret = 0x{ret:X}"); ps4.FreeMemory(pid, mountPointAddr, Marshal.SizeOf(typeof(SceSaveDataMountPoint))); mp = null; } private string Mount(SceSaveDataMount mount, SceSaveDataMountResult mountResult) { var mountAddr = ps4.AllocateMemory(pid, Marshal.SizeOf(typeof(SceSaveDataMount)) + Marshal.SizeOf(typeof(SceSaveDataMountResult))); var mountResultAddr = mountAddr + (uint)Marshal.SizeOf(typeof(SceSaveDataMount)); ps4.WriteMemory(pid, mountAddr, mount); ps4.WriteMemory(pid, mountResultAddr, mountResult); var ret = ps4.Call(pid, stub, libSceSaveDataBase + offsets.sceSaveDataMount, mountAddr, mountResultAddr); WriteLog($"sceSaveDataMount ret = 0x{ret:X}"); if (ret == 0) { mountResult = ps4.ReadMemory(pid, mountResultAddr); ps4.FreeMemory(pid, mountAddr, Marshal.SizeOf(typeof(SceSaveDataMount)) + Marshal.SizeOf(typeof(SceSaveDataMountResult))); return mountResult.mountPoint.data; } ps4.FreeMemory(pid, mountAddr, Marshal.SizeOf(typeof(SceSaveDataMount)) + Marshal.SizeOf(typeof(SceSaveDataMountResult))); return ""; } class SearchEntry { public string dirName; public string title; public string subtitle; public string detail; public string time; public override string ToString() { return dirName; } } private void dirsComboBox_SelectedIndexChanged(object sender, EventArgs e) { titleTextBox.Text = ((SearchEntry)dirsComboBox.SelectedItem).title; subtitleTextBox.Text = ((SearchEntry)dirsComboBox.SelectedItem).subtitle; detailsTextBox.Text = ((SearchEntry)dirsComboBox.SelectedItem).detail; dateTextBox.Text = ((SearchEntry)dirsComboBox.SelectedItem).time; } private void userComboBox_SelectedIndexChanged(object sender, EventArgs e) { user = ((User)userComboBox.SelectedItem).id; } class User { public int id; public string name; public override string ToString() { return name; } } private string[] GetSaveDirectories() { var dirs = new List(); var mem = ps4.AllocateMemory(pid, 0x8000); var path = mem; var buffer = mem + 0x101; ps4.WriteMemory(pid, path, $"/user/home/{GetUser():x}/savedata/"); var ret = (int)ps4.Call(pid, stub, GetSaveDirectoriesAddr, path, buffer); if (ret != -1 && ret != 0) { var bDirs = ps4.ReadMemory(pid, buffer, ret * 0x10); for (var i = 0; i < ret; i++) { var sDir = System.Text.Encoding.UTF8.GetString(PS4DBG.SubArray(bDirs, i * 10, 9)); dirs.Add(sDir); } } ps4.FreeMemory(pid, mem, 0x8000); return dirs.ToArray(); } private User[] GetUsers() { List users = new List(); var mem = ps4.AllocateMemory(pid, 0x1); var ret = (int)ps4.Call(pid, stub, GetUsersAddr, mem); if (ret != -1 && ret != 0) { var buffer = ps4.ReadMemory(pid, mem, (21) * 4); for (int i = 0; i < 4; i++) { var id = BitConverter.ToInt32(buffer, 21 * i); if (id == 0) { continue; } var name = System.Text.Encoding.UTF8.GetString(PS4DBG.SubArray(buffer, i * 21 + 4, 16)); users.Add(new User { id = id, name = name }); } } ps4.FreeMemory(pid, mem, 0x1); return users.ToArray(); } public static bool checkIP(string IP) { return !string.IsNullOrEmpty(IP) && IPAddress.TryParse(IP, out _); } private void payloadButton_Click(object sender, EventArgs e) { try { if (!checkIP(ipTextBox.Text)) { SetStatus("Invalid IP"); return; } var assembly = System.Reflection.Assembly.GetExecutingAssembly(); using (var stream = assembly.GetManifestResourceStream("PS4Saves.ps4debug.bin")) { var buffer = new byte[stream.Length]; stream.Read(buffer, 0, buffer.Length); var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); IAsyncResult result = socket.BeginConnect(new IPEndPoint(IPAddress.Parse(ipTextBox.Text), 9020), null, null); var connected = result.AsyncWaitHandle.WaitOne(3000); if (connected) { socket.Send(buffer, buffer.Length, SocketFlags.None); } SetStatus(connected ? "Payload sent" : "Failed to connect"); socket.Close(); } } catch { SetStatus("Sending payload failed"); } } private void getGamesButton_Click(object sender, EventArgs e) { if (!ps4.IsConnected) { SetStatus("Not connected to ps4"); return; } if (pid == 0) { SetStatus("Don't forget to press setup"); return; } var pm = ps4.GetProcessMaps(pid); if (pm.FindEntry("(NoName)clienthandler") == null) { SetStatus("RPC Stub Not Found"); return; } var dirs = GetSaveDirectories(); gamesComboBox.DataSource = dirs; } private void gamesComboBox_SelectedIndexChanged(object sender, EventArgs e) { selectedGame = (string)gamesComboBox.SelectedItem; } } } ================================================ FILE: PS4Saves.csproj ================================================  Debug AnyCPU {8F8D661C-CCD4-4360-962D-60207A3828BF} WinExe PS4Saves Playstation 4 Save Mounter v2.0 512 true AnyCPU true full false bin\Debug\ DEBUG;TRACE prompt 4 7.1 AnyCPU none true bin\Release\ TRACE prompt 4 7.1 Form Main.cs ================================================ FILE: Program.cs ================================================ using System; using System.Collections.Generic; using System.Windows.Forms; namespace PS4Saves { static class Program { /// /// The main entry point for the application. /// [STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Main()); } } } ================================================ FILE: Properties/AssemblyInfo.cs ================================================ using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("Playstation 4 Save Mounter")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("PS4Saves")] [assembly: AssemblyCopyright("Copyright © 2018 Aida & ChendoChap")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("8f8d661c-ccd4-4360-962d-60207a3828bf")] // Version information for an assembly consists of the following four values: // // Major Version // Minor Version // Build Number // Revision // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.5.0.0")] [assembly: AssemblyFileVersion("1.5.0.0")] ================================================ FILE: README.md ================================================ # Playstation 4 Save Mounter 1.5 ## Summary This program allows you to mount save data with RW permission and a lot more shit, just read this damn thing ### You can * Make decrypted copies of any save (as long as it's encrypted with keys <= 5.05) * Replace saves with modified ones * Replace save files with someone else's save files (share saves) * Create new saves * Export saves to 5.05+ consoles ### You can't * Replace save files with an encrypted save (if it's encrypted with keys > 5.05) * Use this on unexploited consoles ### You need * To make sure you're using a recent ps4debug version, bin of the latest ps4debug (as of 11/14) is included in the download * To be able to run .net framework 2.0 executables (even windows 98 can run this) ## Prerequisites * PS4 5.05 * FTP Client (eg filezilla, ...) ## Instructions ### Mounting saves 1) Load [ps4debug](https://github.com/xemio/ps4debug) 2) Load [FTP](https://github.com/xvortex/ps4-ftp-vtx) 3) Open the tool 4) Enter the ip of your ps4 and click 'Connect' 5) Click 'Setup' & select the user you want to use in the combobox 6) Click 'Get Games' & select the game you want to use in the combobox 7) Click 'Search' & select the save you want to mount 8) Click 'Mount' 9) Your save is now mounted and accessible from ftp in /mnt/pfs/ & in /mnt/sandbox/NPXS20001_000/savedataX (it's the same just a different dir) 10) After you're done copying/replacing files click 'Unmount' ### Creating saves 1) Load [ps4debug](https://github.com/xemio/ps4debug) 2) Load [FTP](https://github.com/xvortex/ps4-ftp-vtx) 3) Open the tool 4) Enter the ip of your ps4 and click 'Connect' 5) Click 'Setup' & select the user you want to use in the combobox 6) Click 'Get Games' & select the game you want to use in the combobox 7) Enter the desired save directory name in the textbox 8) Use the slider to choose the save's size 9) Click 'Create Save' 10) Click 'Search' to refresh the save list ### Exporting Saves to 5.05+ consoles 1) mount the save you want to export. 2) get the param.sfo file from the sce_sys directory 3) open it in a hex editor or a ps4 compatible sfo editor 4) change the psn id to the target's psn id (8 bytes, you get that by copying a save using settings, you'll need to change it to little endian) it's at 0x15C for hex editing... see video for sfo editor 5) save the param.sfo & replace the one in the mounted dir 6) unmount the save and copy the 2 save files sdimg & the .bin to your usb /PS4/SAVEDATA/{psn id}/{titleid}/ 7) remove the sdimg_ prefix from the filename 8) now you should be able to copy the save to the account linked to the psn id (5.05+ console) using system settings ## Important **- you don't need to start a game to modify its saves, it's actually better not to have one open because some games like gow 4 may overwrite parts of a save while you're busy modifying it resulting in a corrupted save.** **- don't replace files in sce_sys directory, it is unnecessary and will probably corrupt your save** **- the workaround method is obsolete since update 1.4** **- some games require you to create your own save data with the appropriate name & size, fallout 4 is such a game. This problem was discussed in [issue #5](https://github.com/ChendoChap/Playstation-4-Save-Mounter/issues/5)** **- Don't forget to regularly make backups of your saves and the savedata database, the ps4 deletes all your saves if the database gets corrupted while this mostly only happens when you actively mess with it, it's always better to be prepared** **- It's possible to mount someone else's encrypted saves but there's currently no 'clean' way to do it. you need to temporarily replace the sdimg_xxx and the xxx.bin files with the ones you downloaded in your user's savedata directory. Be sure to restore the original files after you extracted the save because the ps4 could throw a fit if you reboot while those files are still there. (I'll make this process easier later on)** ## Resources ### Do note that not all of these were made using the latest save mounter version so slight differences are to be expected. ### Videos * exporting saves to 5.05+ consoles (latest version 1.5): [how to resign PS4 saves for different PS4 and profile, fw 5 05 and higher by 'Old Gamer'](https://www.youtube.com/watch?v=OpZ9C-MciZM) * mounting saves, transferring saves to other (regions/title ids) (old version): [PS4 Save Mounter Tutorial (Swap Saves Between Consoles & Games) by 'MODDED WARFARE'](https://www.youtube.com/watch?v=m_h4MsAaXdY) * mounting saves, using other people's decrypted saves (old version): [Playstation 4 Save Mounter Demonstration by 'Sc0rpion'](https://www.youtube.com/watch?v=Atw6480SX5I) ================================================ FILE: functions.cs ================================================ namespace PS4Saves { internal static class functions { internal static byte[] GetSaveDirectories = { 0x55, 0x48, 0x89, 0xE5, 0x48, 0x83, 0xEC, 0x50, 0x48, 0x89, 0x7D, 0xB8, 0x48, 0x89, 0x75, 0xB0, 0x48, 0xB8, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x48, 0x89, 0x45, 0xE8, 0x48, 0xB8, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0x48, 0x89, 0x45, 0xE0, 0x48, 0xB8, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x48, 0x89, 0x45, 0xD8, 0x48, 0xB8, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0x48, 0x89, 0x45, 0xD0, 0x48, 0x8B, 0x55, 0xB8, 0x48, 0x8B, 0x45, 0xE8, 0x48, 0x89, 0xD7, 0xFF, 0xD0, 0x48, 0x89, 0x45, 0xC8, 0x48, 0x83, 0x7D, 0xC8, 0x00, 0x75, 0x0A, 0xB8, 0xFF, 0xFF, 0xFF, 0xFF, 0xE9, 0x88, 0x00, 0x00, 0x00, 0x48, 0x8B, 0x55, 0xC8, 0x48, 0x8B, 0x45, 0xE0, 0x48, 0x89, 0xD7, 0xFF, 0xD0, 0x48, 0x89, 0x45, 0xF8, 0xC7, 0x45, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x48, 0x83, 0x7D, 0xF8, 0x00, 0x74, 0x59, 0x48, 0x8B, 0x45, 0xF8, 0x0F, 0xB6, 0x40, 0x06, 0x3C, 0x04, 0x75, 0x3A, 0x48, 0x8B, 0x45, 0xF8, 0x0F, 0xB6, 0x40, 0x07, 0x3C, 0x09, 0x75, 0x2E, 0x48, 0x8B, 0x45, 0xF8, 0x48, 0x8D, 0x48, 0x08, 0x8B, 0x55, 0xF4, 0x89, 0xD0, 0xC1, 0xE0, 0x02, 0x01, 0xD0, 0x01, 0xC0, 0x48, 0x63, 0xD0, 0x48, 0x8B, 0x45, 0xB0, 0x48, 0x01, 0xC2, 0x48, 0x8B, 0x45, 0xD0, 0x48, 0x89, 0xCE, 0x48, 0x89, 0xD7, 0xFF, 0xD0, 0x83, 0x45, 0xF4, 0x01, 0x48, 0x8B, 0x55, 0xC8, 0x48, 0x8B, 0x45, 0xE0, 0x48, 0x89, 0xD7, 0xFF, 0xD0, 0x48, 0x89, 0x45, 0xF8, 0xEB, 0xA0, 0x48, 0x8B, 0x55, 0xC8, 0x48, 0x8B, 0x45, 0xD8, 0x48, 0x89, 0xD7, 0xFF, 0xD0, 0x8B, 0x45, 0xF4, 0xC9, 0xC3 }; internal static byte[] GetUsers = { 0x55, 0x48, 0x89, 0xE5, 0x48, 0x83, 0xEC, 0x70, 0x48, 0x89, 0x7D, 0x98, 0xC7, 0x45, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x48, 0xB8, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x48, 0x89, 0x45, 0xF0, 0x48, 0xB8, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0x48, 0x89, 0x45, 0xE8, 0x48, 0xB8, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x48, 0x89, 0x45, 0xE0, 0x48, 0x8D, 0x55, 0xC0, 0x48, 0x8B, 0x45, 0xF0, 0x48, 0x89, 0xD7, 0xFF, 0xD0, 0x89, 0x45, 0xDC, 0x83, 0x7D, 0xDC, 0x00, 0x74, 0x0A, 0xB8, 0xFF, 0xFF, 0xFF, 0xFF, 0xE9, 0xB4, 0x00, 0x00, 0x00, 0xC7, 0x45, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x83, 0x7D, 0xF8, 0x03, 0x0F, 0x8F, 0xA0, 0x00, 0x00, 0x00, 0x8B, 0x45, 0xF8, 0x48, 0x98, 0x8B, 0x44, 0x85, 0xC0, 0x85, 0xC0, 0x0F, 0x8E, 0x86, 0x00, 0x00, 0x00, 0x8B, 0x45, 0xF8, 0x48, 0x98, 0x8B, 0x4C, 0x85, 0xC0, 0x48, 0x8D, 0x75, 0xA0, 0x48, 0x8B, 0x45, 0xE8, 0xBA, 0x11, 0x00, 0x00, 0x00, 0x89, 0xCF, 0xFF, 0xD0, 0x89, 0x45, 0xDC, 0x83, 0x7D, 0xDC, 0x00, 0x74, 0x07, 0xB8, 0xFF, 0xFF, 0xFF, 0xFF, 0xEB, 0x68, 0x8B, 0x55, 0xF8, 0x89, 0xD0, 0xC1, 0xE0, 0x02, 0x01, 0xD0, 0xC1, 0xE0, 0x02, 0x01, 0xD0, 0x48, 0x98, 0x48, 0x8D, 0x14, 0x85, 0x00, 0x00, 0x00, 0x00, 0x48, 0x8B, 0x45, 0x98, 0x48, 0x01, 0xC2, 0x8B, 0x45, 0xF8, 0x48, 0x98, 0x8B, 0x44, 0x85, 0xC0, 0x89, 0x02, 0x8B, 0x55, 0xF8, 0x89, 0xD0, 0xC1, 0xE0, 0x02, 0x01, 0xD0, 0xC1, 0xE0, 0x02, 0x01, 0xD0, 0x48, 0x98, 0x48, 0x8D, 0x50, 0x04, 0x48, 0x8B, 0x45, 0x98, 0x48, 0x8D, 0x0C, 0x02, 0x48, 0x8D, 0x55, 0xA0, 0x48, 0x8B, 0x45, 0xE0, 0x48, 0x89, 0xD6, 0x48, 0x89, 0xCF, 0xFF, 0xD0, 0x83, 0x45, 0xFC, 0x01, 0x83, 0x45, 0xF8, 0x01, 0xE9, 0x56, 0xFF, 0xFF, 0xFF, 0x8B, 0x45, 0xFC, 0xC9, 0xC3 }; } } ================================================ FILE: libdebug/PS4DBG.Console.cs ================================================ using System.Text; namespace libdebug { public partial class PS4DBG { //console // packet sizes // send size private const int CMD_CONSOLE_PRINT_PACKET_SIZE = 4; private const int CMD_CONSOLE_NOTIFY_PACKET_SIZE = 8; // console // note: the disconnect command actually uses the console api to end the connection /// /// Reboot console /// public void Reboot() { CheckConnected(); SendCMDPacket(CMDS.CMD_CONSOLE_REBOOT, 0); IsConnected = false; } /// /// Print to serial port /// public void Print(string str) { CheckConnected(); string raw = str + "\0"; SendCMDPacket(CMDS.CMD_CONSOLE_PRINT, CMD_CONSOLE_PRINT_PACKET_SIZE, raw.Length); SendData(Encoding.ASCII.GetBytes(raw), raw.Length); CheckStatus(); } /// /// Notify console /// public void Notify(int messageType, string message) { CheckConnected(); string raw = message + "\0"; SendCMDPacket(CMDS.CMD_CONSOLE_NOTIFY, CMD_CONSOLE_NOTIFY_PACKET_SIZE, messageType, raw.Length); SendData(Encoding.ASCII.GetBytes(raw), raw.Length); CheckStatus(); } /// /// Console information /// public void GetConsoleInformation() { CheckConnected(); SendCMDPacket(CMDS.CMD_CONSOLE_INFO, 0); CheckStatus(); // TODO return the data } } } ================================================ FILE: libdebug/PS4DBG.Debug.cs ================================================ using System; using System.Net; using System.Net.Sockets; using System.Runtime.InteropServices; using System.Threading; namespace libdebug { public partial class PS4DBG { //debug // packet sizes //send size private const int CMD_DEBUG_ATTACH_PACKET_SIZE = 4; private const int CMD_DEBUG_BREAKPT_PACKET_SIZE = 16; private const int CMD_DEBUG_WATCHPT_PACKET_SIZE = 24; private const int CMD_DEBUG_STOPTHR_PACKET_SIZE = 4; private const int CMD_DEBUG_RESUMETHR_PACKET_SIZE = 4; private const int CMD_DEBUG_GETREGS_PACKET_SIZE = 4; private const int CMD_DEBUG_SETREGS_PACKET_SIZE = 8; private const int CMD_DEBUG_STOPGO_PACKET_SIZE = 4; private const int CMD_DEBUG_THRINFO_PACKET_SIZE = 4; //receive size private const int DEBUG_INTERRUPT_SIZE = 0x4A0; private const int DEBUG_THRINFO_SIZE = 40; private const int DEBUG_REGS_SIZE = 0xB0; private const int DEBUG_FPREGS_SIZE = 0x340; private const int DEBUG_DBGREGS_SIZE = 0x80; [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct DebuggerInterruptPacket { public uint lwpid; public uint status; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 40)] public string tdname; public regs reg64; public fpregs savefpu; public dbregs dbreg64; } /// /// Debugger interrupt callback /// /// Thread identifier /// status /// Thread name /// Registers /// Floating point registers /// Debug registers public delegate void DebuggerInterruptCallback(uint lwpid, uint status, string tdname, regs regs, fpregs fpregs, dbregs dbregs); private void DebuggerThread(object obj) { DebuggerInterruptCallback callback = (DebuggerInterruptCallback)obj; IPAddress ip = IPAddress.Parse("0.0.0.0"); IPEndPoint endpoint = new IPEndPoint(ip, PS4DBG_DEBUG_PORT); Socket server = new Socket(ip.AddressFamily, SocketType.Stream, ProtocolType.Tcp); server.Bind(endpoint); server.Listen(0); IsDebugging = true; Socket cl = server.Accept(); cl.NoDelay = true; cl.Blocking = false; while (IsDebugging) { if (cl.Available == DEBUG_INTERRUPT_SIZE) { byte[] data = new byte[DEBUG_INTERRUPT_SIZE]; int bytes = cl.Receive(data, DEBUG_INTERRUPT_SIZE, SocketFlags.None); if (bytes == DEBUG_INTERRUPT_SIZE) { DebuggerInterruptPacket packet = (DebuggerInterruptPacket)GetObjectFromBytes(data, typeof(DebuggerInterruptPacket)); callback(packet.lwpid, packet.status, packet.tdname, packet.reg64, packet.savefpu, packet.dbreg64); } } Thread.Sleep(100); } server.Close(); } /// /// Attach the debugger /// /// Process ID /// DebuggerInterruptCallback implementation /// public void AttachDebugger(int pid, DebuggerInterruptCallback callback) { CheckConnected(); if (IsDebugging || debugThread != null) { throw new Exception("libdbg: debugger already running?"); } IsDebugging = false; debugThread = new Thread(DebuggerThread); debugThread.Start(callback); // wait until server is started while (!IsDebugging) { Thread.Sleep(100); } SendCMDPacket(CMDS.CMD_DEBUG_ATTACH, CMD_DEBUG_ATTACH_PACKET_SIZE, pid); CheckStatus(); } /// /// Detach the debugger /// /// public void DetachDebugger() { CheckConnected(); SendCMDPacket(CMDS.CMD_DEBUG_DETACH, 0); CheckStatus(); if (IsDebugging && debugThread != null) { IsDebugging = false; debugThread.Join(); debugThread = null; } } /// /// Stop the current process /// /// public void ProcessStop() { CheckConnected(); CheckDebugging(); SendCMDPacket(CMDS.CMD_DEBUG_STOPGO, CMD_DEBUG_STOPGO_PACKET_SIZE, 1); CheckStatus(); } /// /// Kill the current process, it will detach before doing so /// /// public void ProcessKill() { CheckConnected(); CheckDebugging(); SendCMDPacket(CMDS.CMD_DEBUG_STOPGO, CMD_DEBUG_STOPGO_PACKET_SIZE, 2); CheckStatus(); } /// /// Resume the current process /// /// public void ProcessResume() { CheckConnected(); CheckDebugging(); SendCMDPacket(CMDS.CMD_DEBUG_STOPGO, CMD_DEBUG_STOPGO_PACKET_SIZE, 0); CheckStatus(); } /// /// Change breakpoint, to remove said breakpoint send the same index but disable it (address is ignored) /// /// Index /// Enabled /// Address /// public void ChangeBreakpoint(int index, bool enabled, ulong address) { CheckConnected(); CheckDebugging(); if (index >= MAX_BREAKPOINTS) { throw new Exception("libdbg: breakpoint index out of range"); } SendCMDPacket(CMDS.CMD_DEBUG_BREAKPT, CMD_DEBUG_BREAKPT_PACKET_SIZE, index, Convert.ToInt32(enabled), address); CheckStatus(); } /// /// Change watchpoint /// /// Index /// Enabled /// Length /// Break type /// Address /// public void ChangeWatchpoint(int index, bool enabled, WATCHPT_LENGTH length, WATCHPT_BREAKTYPE breaktype, ulong address) { CheckConnected(); CheckDebugging(); if (index >= MAX_WATCHPOINTS) { throw new Exception("libdbg: watchpoint index out of range"); } SendCMDPacket(CMDS.CMD_DEBUG_WATCHPT, CMD_DEBUG_WATCHPT_PACKET_SIZE, index, Convert.ToInt32(enabled), (uint)length, (uint)breaktype, address); CheckStatus(); } /// /// Get a list of threads from the current process /// /// public uint[] GetThreadList() { CheckConnected(); CheckDebugging(); SendCMDPacket(CMDS.CMD_DEBUG_THREADS, 0); CheckStatus(); byte[] data = new byte[sizeof(int)]; sock.Receive(data, sizeof(int), SocketFlags.None); int number = BitConverter.ToInt32(data, 0); byte[] threads = ReceiveData(number * sizeof(uint)); uint[] thrlist = new uint[number]; for (int i = 0; i < number; i++) { thrlist[i] = BitConverter.ToUInt32(threads, i * sizeof(uint)); } return thrlist; } /// /// Get thread information /// /// /// Thread identifier public ThreadInfo GetThreadInfo(uint lwpid) { CheckConnected(); CheckDebugging(); SendCMDPacket(CMDS.CMD_DEBUG_THRINFO, CMD_DEBUG_THRINFO_PACKET_SIZE, lwpid); CheckStatus(); return (ThreadInfo)GetObjectFromBytes(ReceiveData(DEBUG_THRINFO_SIZE), typeof(ThreadInfo)); } /// /// Stop a thread from running /// /// Thread id /// public void StopThread(uint lwpid) { CheckConnected(); CheckDebugging(); SendCMDPacket(CMDS.CMD_DEBUG_STOPTHR, CMD_DEBUG_STOPTHR_PACKET_SIZE, lwpid); CheckStatus(); } /// /// Resume a thread from being stopped /// /// Thread id /// public void ResumeThread(uint lwpid) { CheckConnected(); CheckDebugging(); SendCMDPacket(CMDS.CMD_DEBUG_RESUMETHR, CMD_DEBUG_RESUMETHR_PACKET_SIZE, lwpid); CheckStatus(); } /// /// Get registers from thread /// /// Thread id /// public regs GetRegisters(uint lwpid) { CheckConnected(); CheckDebugging(); SendCMDPacket(CMDS.CMD_DEBUG_GETREGS, CMD_DEBUG_GETREGS_PACKET_SIZE, lwpid); CheckStatus(); return (regs)GetObjectFromBytes(ReceiveData(DEBUG_REGS_SIZE), typeof(regs)); } /// /// Set thread registers /// /// Thread id /// Register data /// public void SetRegisters(uint lwpid, regs regs) { CheckConnected(); CheckDebugging(); SendCMDPacket(CMDS.CMD_DEBUG_SETREGS, CMD_DEBUG_SETREGS_PACKET_SIZE, lwpid, DEBUG_REGS_SIZE); CheckStatus(); SendData(GetBytesFromObject(regs), DEBUG_REGS_SIZE); CheckStatus(); } /// /// Get floating point registers from thread /// /// Thread id /// public fpregs GetFloatRegisters(uint lwpid) { CheckConnected(); CheckDebugging(); SendCMDPacket(CMDS.CMD_DEBUG_GETFPREGS, CMD_DEBUG_GETREGS_PACKET_SIZE, lwpid); CheckStatus(); return (fpregs)GetObjectFromBytes(ReceiveData(DEBUG_FPREGS_SIZE), typeof(fpregs)); } /// /// Set floating point thread registers /// /// Thread id /// Floating point register data /// public void SetFloatRegisters(uint lwpid, fpregs fpregs) { CheckConnected(); CheckDebugging(); SendCMDPacket(CMDS.CMD_DEBUG_SETFPREGS, CMD_DEBUG_SETREGS_PACKET_SIZE, lwpid, DEBUG_FPREGS_SIZE); CheckStatus(); SendData(GetBytesFromObject(fpregs), DEBUG_FPREGS_SIZE); CheckStatus(); } /// /// Get debug registers from thread /// /// Thread id /// public dbregs GetDebugRegisters(uint lwpid) { CheckConnected(); CheckDebugging(); SendCMDPacket(CMDS.CMD_DEBUG_GETDBGREGS, CMD_DEBUG_GETREGS_PACKET_SIZE, lwpid); CheckStatus(); return (dbregs)GetObjectFromBytes(ReceiveData(DEBUG_DBGREGS_SIZE), typeof(dbregs)); } /// /// Set debug thread registers /// /// Thread id /// debug register data /// public void SetDebugRegisters(uint lwpid, dbregs dbregs) { CheckConnected(); CheckDebugging(); SendCMDPacket(CMDS.CMD_DEBUG_SETDBGREGS, CMD_DEBUG_SETREGS_PACKET_SIZE, lwpid, DEBUG_DBGREGS_SIZE); CheckStatus(); SendData(GetBytesFromObject(dbregs), DEBUG_DBGREGS_SIZE); CheckStatus(); } /// /// Executes a single instruction /// public void SingleStep() { CheckConnected(); CheckDebugging(); SendCMDPacket(CMDS.CMD_DEBUG_SINGLESTEP, 0); CheckStatus(); } } } ================================================ FILE: libdebug/PS4DBG.Kernel.cs ================================================ using System; namespace libdebug { public partial class PS4DBG { // kernel //packet sizes //send size private const int CMD_KERN_READ_PACKET_SIZE = 12; private const int CMD_KERN_WRITE_PACKET_SIZE = 12; //receive size private const int KERN_BASE_SIZE = 8; /// /// Get kernel base address /// /// public ulong KernelBase() { CheckConnected(); SendCMDPacket(CMDS.CMD_KERN_BASE, 0); CheckStatus(); return BitConverter.ToUInt64(ReceiveData(KERN_BASE_SIZE), 0); } /// /// Read memory from kernel /// /// Memory address /// Data length /// public byte[] KernelReadMemory(ulong address, int length) { CheckConnected(); SendCMDPacket(CMDS.CMD_KERN_READ, CMD_KERN_READ_PACKET_SIZE, address, length); CheckStatus(); return ReceiveData(length); } /// /// Write memory in kernel /// /// Memory address /// Data public void KernelWriteMemory(ulong address, byte[] data) { CheckConnected(); SendCMDPacket(CMDS.CMD_KERN_WRITE, CMD_KERN_WRITE_PACKET_SIZE, address, data.Length); CheckStatus(); SendData(data, data.Length); CheckStatus(); } } } ================================================ FILE: libdebug/PS4DBG.Proc.cs ================================================ using System; using System.Collections.Generic; using System.IO; using System.Net.Sockets; using System.Runtime.InteropServices; using System.Text; namespace libdebug { public partial class PS4DBG { //proc // packet sizes // send size private const int CMD_PROC_READ_PACKET_SIZE = 16; private const int CMD_PROC_WRITE_PACKET_SIZE = 16; private const int CMD_PROC_MAPS_PACKET_SIZE = 4; private const int CMD_PROC_INSTALL_PACKET_SIZE = 4; private const int CMD_PROC_CALL_PACKET_SIZE = 68; private const int CMD_PROC_ELF_PACKET_SIZE = 8; private const int CMD_PROC_PROTECT_PACKET_SIZE = 20; private const int CMD_PROC_SCAN_PACKET_SIZE = 10; private const int CMD_PROC_INFO_PACKET_SIZE = 4; private const int CMD_PROC_ALLOC_PACKET_SIZE = 8; private const int CMD_PROC_FREE_PACKET_SIZE = 16; // receive size private const int PROC_LIST_ENTRY_SIZE = 36; private const int PROC_MAP_ENTRY_SIZE = 58; private const int PROC_INSTALL_SIZE = 8; private const int PROC_CALL_SIZE = 12; private const int PROC_PROC_INFO_SIZE = 188; private const int PROC_ALLOC_SIZE = 8; /// /// Get current process list /// /// public ProcessList GetProcessList() { CheckConnected(); SendCMDPacket(CMDS.CMD_PROC_LIST, 0); CheckStatus(); // recv count byte[] bytes = new byte[4]; sock.Receive(bytes, 4, SocketFlags.None); int number = BitConverter.ToInt32(bytes, 0); // recv data byte[] data = ReceiveData(number * PROC_LIST_ENTRY_SIZE); // parse data string[] names = new string[number]; int[] pids = new int[number]; for (int i = 0; i < number; i++) { int offset = i * PROC_LIST_ENTRY_SIZE; names[i] = ConvertASCII(data, offset); pids[i] = BitConverter.ToInt32(data, offset + 32); } return new ProcessList(number, names, pids); } /// /// Read memory /// /// Process ID /// Memory address /// Data length /// public byte[] ReadMemory(int pid, ulong address, int length) { CheckConnected(); SendCMDPacket(CMDS.CMD_PROC_READ, CMD_PROC_READ_PACKET_SIZE, pid, address, length); CheckStatus(); return ReceiveData(length); } /// /// Write memory /// /// Process ID /// Memory address /// Data public void WriteMemory(int pid, ulong address, byte[] data) { CheckConnected(); SendCMDPacket(CMDS.CMD_PROC_WRITE, CMD_PROC_WRITE_PACKET_SIZE, pid, address, data.Length); CheckStatus(); SendData(data, data.Length); CheckStatus(); } /// /// Get process memory maps /// /// Process ID /// public ProcessMap GetProcessMaps(int pid) { CheckConnected(); SendCMDPacket(CMDS.CMD_PROC_MAPS, CMD_PROC_MAPS_PACKET_SIZE, pid); CheckStatus(); // recv count byte[] bnumber = new byte[4]; sock.Receive(bnumber, 4, SocketFlags.None); int number = BitConverter.ToInt32(bnumber, 0); // recv data byte[] data = ReceiveData(number * PROC_MAP_ENTRY_SIZE); // parse data MemoryEntry[] entries = new MemoryEntry[number]; for (int i = 0; i < number; i++) { int offset = i * PROC_MAP_ENTRY_SIZE; entries[i] = new MemoryEntry { name = ConvertASCII(data, offset), start = BitConverter.ToUInt64(data, offset + 32), end = BitConverter.ToUInt64(data, offset + 40), offset = BitConverter.ToUInt64(data, offset + 48), prot = BitConverter.ToUInt16(data, offset + 56) }; } return new ProcessMap(pid, entries); } /// /// Install RPC into a process, this returns a stub address that you should pass into call functions /// /// Process ID /// public ulong InstallRPC(int pid) { CheckConnected(); SendCMDPacket(CMDS.CMD_PROC_INTALL, CMD_PROC_INSTALL_PACKET_SIZE, pid); CheckStatus(); return BitConverter.ToUInt64(ReceiveData(PROC_INSTALL_SIZE), 0); } /// /// Call function (returns rax) /// /// Process ID /// Stub address from InstallRPC /// Address to call /// Arguments array /// public ulong Call(int pid, ulong rpcstub, ulong address, params object[] args) { CheckConnected(); // need to do this in a custom format CMDPacket packet = new CMDPacket { magic = CMD_PACKET_MAGIC, cmd = (uint) CMDS.CMD_PROC_CALL, datalen = (uint) CMD_PROC_CALL_PACKET_SIZE }; SendData(GetBytesFromObject(packet), CMD_PACKET_SIZE); MemoryStream rs = new MemoryStream(); rs.Write(BitConverter.GetBytes(pid), 0, sizeof(int)); rs.Write(BitConverter.GetBytes(rpcstub), 0, sizeof(ulong)); rs.Write(BitConverter.GetBytes(address), 0, sizeof(ulong)); int num = 0; foreach (object arg in args) { byte[] bytes = new byte[8]; switch (arg) { case char c: { byte[] tmp = BitConverter.GetBytes(c); Buffer.BlockCopy(tmp, 0, bytes, 0, sizeof(char)); byte[] pad = new byte[sizeof(ulong) - sizeof(char)]; Buffer.BlockCopy(pad, 0, bytes, sizeof(char), pad.Length); break; } case byte b: { byte[] tmp = BitConverter.GetBytes(b); Buffer.BlockCopy(tmp, 0, bytes, 0, sizeof(byte)); byte[] pad = new byte[sizeof(ulong) - sizeof(byte)]; Buffer.BlockCopy(pad, 0, bytes, sizeof(byte), pad.Length); break; } case short s: { byte[] tmp = BitConverter.GetBytes(s); Buffer.BlockCopy(tmp, 0, bytes, 0, sizeof(short)); byte[] pad = new byte[sizeof(ulong) - sizeof(short)]; Buffer.BlockCopy(pad, 0, bytes, sizeof(short), pad.Length); break; } case ushort us: { byte[] tmp = BitConverter.GetBytes(us); Buffer.BlockCopy(tmp, 0, bytes, 0, sizeof(ushort)); byte[] pad = new byte[sizeof(ulong) - sizeof(ushort)]; Buffer.BlockCopy(pad, 0, bytes, sizeof(ushort), pad.Length); break; } case int i: { byte[] tmp = BitConverter.GetBytes(i); Buffer.BlockCopy(tmp, 0, bytes, 0, sizeof(int)); byte[] pad = new byte[sizeof(ulong) - sizeof(int)]; Buffer.BlockCopy(pad, 0, bytes, sizeof(int), pad.Length); break; } case uint ui: { byte[] tmp = BitConverter.GetBytes(ui); Buffer.BlockCopy(tmp, 0, bytes, 0, sizeof(uint)); byte[] pad = new byte[sizeof(ulong) - sizeof(uint)]; Buffer.BlockCopy(pad, 0, bytes, sizeof(uint), pad.Length); break; } case long l: { byte[] tmp = BitConverter.GetBytes(l); Buffer.BlockCopy(tmp, 0, bytes, 0, sizeof(long)); break; } case ulong ul: { byte[] tmp = BitConverter.GetBytes(ul); Buffer.BlockCopy(tmp, 0, bytes, 0, sizeof(ulong)); break; } } rs.Write(bytes, 0, bytes.Length); num++; } if (num > 6) { throw new Exception("libdbg: too many arguments"); } if (num < 6) { for (int i = 0; i < (6 - num); i++) { rs.Write(BitConverter.GetBytes((ulong)0), 0, sizeof(ulong)); } } SendData(rs.ToArray(), CMD_PROC_CALL_PACKET_SIZE); rs.Dispose(); CheckStatus(); byte[] data = ReceiveData(PROC_CALL_SIZE); return BitConverter.ToUInt64(data, 4); } /// /// Load elf /// /// Process ID /// Elf public void LoadElf(int pid, byte[] elf) { CheckConnected(); SendCMDPacket(CMDS.CMD_PROC_ELF, CMD_PROC_ELF_PACKET_SIZE, pid, (uint)elf.Length); CheckStatus(); SendData(elf, elf.Length); CheckStatus(); } /// /// Load elf /// /// Process ID /// Elf filename public void LoadElf(int pid, string filename) { LoadElf(pid, File.ReadAllBytes(filename)); } public enum ScanValueType : byte { valTypeUInt8 = 0, valTypeInt8, valTypeUInt16, valTypeInt16, valTypeUInt32, valTypeInt32, valTypeUInt64, valTypeInt64, valTypeFloat, valTypeDouble, valTypeArrBytes, valTypeString } public enum ScanCompareType : byte { ExactValue = 0, FuzzyValue, BiggerThan, SmallerThan, ValueBetween, IncreasedValue, IncreasedValueBy, DecreasedValue, DecreasedValueBy, ChangedValue, UnchangedValue, UnknownInitialValue } public List ScanProcess(int pid, ScanCompareType compareType, T value, T extraValue = default) { CheckConnected(); int typeLength = 0; ScanValueType valueType; byte[] valueBuffer, extraValueBuffer = null; // fill in variables switch (value) { case bool b: valueType = ScanValueType.valTypeUInt8; typeLength = 1; valueBuffer = BitConverter.GetBytes(b); if (extraValue != null) extraValueBuffer = BitConverter.GetBytes((bool)(object)extraValue); break; case sbyte sb: valueType = ScanValueType.valTypeInt8; valueBuffer = BitConverter.GetBytes(sb); typeLength = 1; if (extraValue != null) extraValueBuffer = BitConverter.GetBytes((sbyte)(object)extraValue); break; case byte b: valueType = ScanValueType.valTypeUInt8; valueBuffer = BitConverter.GetBytes(b); typeLength = 1; if (extraValue != null) extraValueBuffer = BitConverter.GetBytes((byte)(object)extraValue); break; case short s: valueType = ScanValueType.valTypeInt16; valueBuffer = BitConverter.GetBytes(s); typeLength = 2; if (extraValue != null) extraValueBuffer = BitConverter.GetBytes((short)(object)extraValue); break; case ushort us: valueType = ScanValueType.valTypeUInt16; valueBuffer = BitConverter.GetBytes(us); typeLength = 2; if (extraValue != null) extraValueBuffer = BitConverter.GetBytes((ushort)(object)extraValue); break; case int i: valueType = ScanValueType.valTypeInt32; valueBuffer = BitConverter.GetBytes(i); typeLength = 4; if (extraValue != null) extraValueBuffer = BitConverter.GetBytes((int)(object)extraValue); break; case uint ui: valueType = ScanValueType.valTypeUInt32; valueBuffer = BitConverter.GetBytes(ui); typeLength = 4; if (extraValue != null) extraValueBuffer = BitConverter.GetBytes((uint)(object)extraValue); break; case long l: valueType = ScanValueType.valTypeInt64; valueBuffer = BitConverter.GetBytes(l); typeLength = 8; if (extraValue != null) extraValueBuffer = BitConverter.GetBytes((long)(object)extraValue); break; case ulong ul: valueType = ScanValueType.valTypeUInt64; valueBuffer = BitConverter.GetBytes(ul); typeLength = 8; if (extraValue != null) extraValueBuffer = BitConverter.GetBytes((ulong)(object)extraValue); break; case float f: valueType = ScanValueType.valTypeFloat; valueBuffer = BitConverter.GetBytes(f); typeLength = 4; if (extraValue != null) extraValueBuffer = BitConverter.GetBytes((float)(object)extraValue); break; case double d: valueType = ScanValueType.valTypeDouble; valueBuffer = BitConverter.GetBytes(d); typeLength = 8; if (extraValue != null) extraValueBuffer = BitConverter.GetBytes((double)(object)extraValue); break; case string s: valueType = ScanValueType.valTypeString; valueBuffer = Encoding.ASCII.GetBytes(s); typeLength = valueBuffer.Length; break; case byte[] ba: valueType = ScanValueType.valTypeArrBytes; valueBuffer = ba; typeLength = valueBuffer.Length; break; default: throw new NotSupportedException("Requested scan value type is not supported! (Feed in Byte[] instead.)"); } // send packet SendCMDPacket(CMDS.CMD_PROC_SCAN, CMD_PROC_SCAN_PACKET_SIZE, pid, (byte)valueType, (byte)compareType, (int)(extraValue == null ? typeLength : typeLength * 2)); CheckStatus(); SendData(valueBuffer, typeLength); if (extraValueBuffer != null) { SendData(extraValueBuffer, typeLength); } CheckStatus(); // receive results int save = sock.ReceiveTimeout; sock.ReceiveTimeout = Int32.MaxValue; List results = new List(); while(true) { ulong result = BitConverter.ToUInt64(ReceiveData(sizeof(ulong)), 0); if(result == 0xFFFFFFFFFFFFFFFF) { break; } results.Add(result); } sock.ReceiveTimeout = save; return results; } /// /// Changes protection on pages in range /// /// Process ID /// Address /// Length /// New protection /// public void ChangeProtection(int pid, ulong address, uint length, VM_PROTECTIONS newProt) { CheckConnected(); SendCMDPacket(CMDS.CMD_PROC_PROTECT, CMD_PROC_PROTECT_PACKET_SIZE, pid, address, length, (uint)newProt); CheckStatus(); } /// /// Get process information /// /// Process ID /// public ProcessInfo GetProcessInfo(int pid) { CheckConnected(); SendCMDPacket(CMDS.CMD_PROC_INFO, CMD_PROC_INFO_PACKET_SIZE, pid); CheckStatus(); byte[] data = ReceiveData(PROC_PROC_INFO_SIZE); return (ProcessInfo)GetObjectFromBytes(data, typeof(ProcessInfo)); } /// /// Allocate RWX memory in the process space /// /// Process ID /// Size of memory allocation /// public ulong AllocateMemory(int pid, int length) { CheckConnected(); SendCMDPacket(CMDS.CMD_PROC_ALLOC, CMD_PROC_ALLOC_PACKET_SIZE, pid, length); CheckStatus(); return BitConverter.ToUInt64(ReceiveData(PROC_ALLOC_SIZE), 0); } /// /// Free memory in the process space /// /// Process ID /// Address of the memory allocation /// Size of memory allocation /// public void FreeMemory(int pid, ulong address, int length) { CheckConnected(); SendCMDPacket(CMDS.CMD_PROC_FREE, CMD_PROC_FREE_PACKET_SIZE, pid, address, length); CheckStatus(); } public T ReadMemory(int pid, ulong address) { if (typeof(T) == typeof(string)) { string str = ""; ulong i = 0; while (true) { byte value = ReadMemory(pid, address + i, sizeof(byte))[0]; if (value == 0) { break; } str += Convert.ToChar(value); i++; } return (T)(object)str; } if (typeof(T) == typeof(byte[])) { throw new NotSupportedException("byte arrays are not supported, use ReadMemory(int pid, ulong address, int size)"); } return (T)GetObjectFromBytes(ReadMemory(pid, address, Marshal.SizeOf(typeof(T))), typeof(T)); } public void WriteMemory(int pid, ulong address, T value) { if (typeof(T) == typeof(string)) { WriteMemory(pid, address, Encoding.ASCII.GetBytes((string)(object)value + (char)0x0)); return; } if (typeof(T) == typeof(byte[])) { WriteMemory(pid, address, (byte[])(object)value); return; } WriteMemory(pid, address, GetBytesFromObject(value)); } } } ================================================ FILE: libdebug/PS4DBG.cs ================================================ using System; using System.IO; using System.Net; using System.Net.Sockets; using System.Runtime.InteropServices; using System.Text; using System.Threading; namespace libdebug { public partial class PS4DBG { private Socket sock = null; private IPEndPoint enp = null; public bool IsConnected { get; private set; } = false; public bool IsDebugging { get; private set; } = false; private Thread debugThread = null; // some global values private const string LIBRARY_VERSION = "1.2"; private const int PS4DBG_PORT = 744; private const int PS4DBG_DEBUG_PORT = 755; private const int NET_MAX_LENGTH = 8192; private const int BROADCAST_PORT = 1010; private const uint BROADCAST_MAGIC = 0xFFFFAAAA; // from protocol.h // each packet starts with the magic // each C# base type can translate into a packet field // some packets, such as write take an additional data whose length will be specified in the cmd packet data field structure specific to that cmd type // ushort - 2 bytes | uint - 4 bytes | ulong - 8 bytes private const uint CMD_PACKET_MAGIC = 0xFFAABBCC; // from debug.h //struct debug_breakpoint { // uint32_t valid; // uint64_t address; // uint8_t original; //}; public static uint MAX_BREAKPOINTS = 10; public static uint MAX_WATCHPOINTS = 4; // struct cmd_packet { // uint32_t magic; // uint32_t cmd; // uint32_t datalen; // // (field not actually part of packet, comes after) // uint8_t* data; // } // __attribute__((packed)); // #define CMD_PACKET_SIZE 12 private const int CMD_PACKET_SIZE = 12; public enum CMDS : uint { CMD_VERSION = 0xBD000001, CMD_PROC_LIST = 0xBDAA0001, CMD_PROC_READ = 0xBDAA0002, CMD_PROC_WRITE = 0xBDAA0003, CMD_PROC_MAPS = 0xBDAA0004, CMD_PROC_INTALL = 0xBDAA0005, CMD_PROC_CALL = 0xBDAA0006, CMD_PROC_ELF = 0xBDAA0007, CMD_PROC_PROTECT = 0xBDAA0008, CMD_PROC_SCAN = 0xBDAA0009, CMD_PROC_INFO = 0xBDAA000A, CMD_PROC_ALLOC = 0xBDAA000B, CMD_PROC_FREE = 0xBDAA000C, CMD_DEBUG_ATTACH = 0xBDBB0001, CMD_DEBUG_DETACH = 0xBDBB0002, CMD_DEBUG_BREAKPT = 0xBDBB0003, CMD_DEBUG_WATCHPT = 0xBDBB0004, CMD_DEBUG_THREADS = 0xBDBB0005, CMD_DEBUG_STOPTHR = 0xBDBB0006, CMD_DEBUG_RESUMETHR = 0xBDBB0007, CMD_DEBUG_GETREGS = 0xBDBB0008, CMD_DEBUG_SETREGS = 0xBDBB0009, CMD_DEBUG_GETFPREGS = 0xBDBB000A, CMD_DEBUG_SETFPREGS = 0xBDBB000B, CMD_DEBUG_GETDBGREGS = 0xBDBB000C, CMD_DEBUG_SETDBGREGS = 0xBDBB000D, CMD_DEBUG_STOPGO = 0xBDBB0010, CMD_DEBUG_THRINFO = 0xBDBB0011, CMD_DEBUG_SINGLESTEP = 0xBDBB0012, CMD_KERN_BASE = 0xBDCC0001, CMD_KERN_READ = 0xBDCC0002, CMD_KERN_WRITE = 0xBDCC0003, CMD_CONSOLE_REBOOT = 0xBDDD0001, CMD_CONSOLE_END = 0xBDDD0002, CMD_CONSOLE_PRINT = 0xBDDD0003, CMD_CONSOLE_NOTIFY = 0xBDDD0004, CMD_CONSOLE_INFO = 0xBDDD0005, }; public enum CMD_STATUS : uint { CMD_SUCCESS = 0x80000000, CMD_ERROR = 0xF0000001, CMD_TOO_MUCH_DATA = 0xF0000002, CMD_DATA_NULL = 0xF0000003, CMD_ALREADY_DEBUG = 0xF0000004, CMD_INVALID_INDEX = 0xF0000005 }; [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct CMDPacket { public uint magic; public uint cmd; public uint datalen; } // enums public enum VM_PROTECTIONS : uint { VM_PROT_NONE = 0x00, VM_PROT_READ = 0x01, VM_PROT_WRITE = 0x02, VM_PROT_EXECUTE = 0x04, VM_PROT_DEFAULT = (VM_PROT_READ | VM_PROT_WRITE), VM_PROT_ALL = (VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE), VM_PROT_NO_CHANGE = 0x08, VM_PROT_COPY = 0x10, VM_PROT_WANTS_COPY = 0x10 }; public enum WATCHPT_LENGTH : uint { DBREG_DR7_LEN_1 = 0x00, /* 1 byte length */ DBREG_DR7_LEN_2 = 0x01, DBREG_DR7_LEN_4 = 0x03, DBREG_DR7_LEN_8 = 0x02, }; public enum WATCHPT_BREAKTYPE : uint { DBREG_DR7_EXEC = 0x00, /* break on execute */ DBREG_DR7_WRONLY = 0x01, /* break on write */ DBREG_DR7_RDWR = 0x03, /* break on read or write */ }; // General helper functions, make code cleaner private static string ConvertASCII(byte[] data, int offset) { int length = Array.IndexOf(data, 0, offset) - offset; if (length < 0) { length = data.Length - offset; } return Encoding.ASCII.GetString(data, offset, length); } public static byte[] SubArray(byte[] data, int offset, int length) { byte[] bytes = new byte[length]; Buffer.BlockCopy(data, offset, bytes, 0, length); return bytes; } public static object GetObjectFromBytes(byte[] buffer, Type type) { int size = Marshal.SizeOf(type); IntPtr ptr = Marshal.AllocHGlobal(size); Marshal.Copy(buffer, 0, ptr, size); object r = Marshal.PtrToStructure(ptr, type); Marshal.FreeHGlobal(ptr); return r; } private static byte[] GetBytesFromObject(object obj) { int size = Marshal.SizeOf(obj); byte[] bytes = new byte[size]; IntPtr ptr = Marshal.AllocHGlobal(size); Marshal.StructureToPtr(obj, ptr, false); Marshal.Copy(ptr, bytes, 0, size); Marshal.FreeHGlobal(ptr); return bytes; } // General networking functions private static IPAddress GetBroadcastAddress(IPAddress address, IPAddress subnetMask) { byte[] ipAdressBytes = address.GetAddressBytes(); byte[] subnetMaskBytes = subnetMask.GetAddressBytes(); byte[] broadcastAddress = new byte[ipAdressBytes.Length]; for (int i = 0; i < broadcastAddress.Length; i++) { broadcastAddress[i] = (byte)(ipAdressBytes[i] | (subnetMaskBytes[i] ^ 255)); } return new IPAddress(broadcastAddress); } private void SendCMDPacket(CMDS cmd, int length, params object[] fields) { CMDPacket packet = new CMDPacket { magic = CMD_PACKET_MAGIC, cmd = (uint) cmd, datalen = (uint) length }; byte[] data = null; if (length > 0) { MemoryStream rs = new MemoryStream(); foreach (object field in fields) { byte[] bytes = null; switch (field) { case char c: bytes = BitConverter.GetBytes(c); break; case byte b: bytes = BitConverter.GetBytes(b); break; case short s: bytes = BitConverter.GetBytes(s); break; case ushort us: bytes = BitConverter.GetBytes(us); break; case int i: bytes = BitConverter.GetBytes(i); break; case uint u: bytes = BitConverter.GetBytes(u); break; case long l: bytes = BitConverter.GetBytes(l); break; case ulong ul: bytes = BitConverter.GetBytes(ul); break; case byte[] ba: bytes = ba; break; } if (bytes != null) rs.Write(bytes, 0, bytes.Length); } data = rs.ToArray(); rs.Dispose(); } SendData(GetBytesFromObject(packet), CMD_PACKET_SIZE); if (data != null) { SendData(data, length); } } private void SendData(byte[] data, int length) { int left = length; int offset = 0; int sent = 0; while (left > 0) { if (left > NET_MAX_LENGTH) { byte[] bytes = SubArray(data, offset, NET_MAX_LENGTH); sent = sock.Send(bytes, NET_MAX_LENGTH, SocketFlags.None); } else { byte[] bytes = SubArray(data, offset, left); sent = sock.Send(bytes, left, SocketFlags.None); } offset += sent; left -= sent; } } private byte[] ReceiveData(int length) { MemoryStream s = new MemoryStream(); int left = length; int recv = 0; while (left > 0) { byte[] b = new byte[NET_MAX_LENGTH]; recv = sock.Receive(b, NET_MAX_LENGTH, SocketFlags.None); s.Write(b, 0, recv); left -= recv; } byte[] data = s.ToArray(); s.Dispose(); GC.Collect(); return data; } private CMD_STATUS ReceiveStatus() { byte[] status = new byte[4]; sock.Receive(status, 4, SocketFlags.None); return (CMD_STATUS)BitConverter.ToUInt32(status, 0); } private void CheckStatus() { CMD_STATUS status = ReceiveStatus(); if (status != CMD_STATUS.CMD_SUCCESS) { throw new Exception("libdbg status " + ((uint)status).ToString("X")); } } private void CheckConnected() { if (!IsConnected) { throw new Exception("libdbg: not connected"); } } private void CheckDebugging() { if (!IsDebugging) { throw new Exception("libdbg: not debugging"); } } public PS4DBG() { enp = null; sock = null; } /// /// Initializes PS4DBG class /// /// PlayStation 4 address public PS4DBG(IPAddress addr) { enp = new IPEndPoint(addr, PS4DBG_PORT); sock = new Socket(enp.AddressFamily, SocketType.Stream, ProtocolType.Tcp); } /// /// Initializes PS4DBG class /// /// PlayStation 4 ip address public PS4DBG(string ip) { IPAddress addr = null; try { addr = IPAddress.Parse(ip); } catch (FormatException ex) { throw ex; } enp = new IPEndPoint(addr, PS4DBG_PORT); sock = new Socket(enp.AddressFamily, SocketType.Stream, ProtocolType.Tcp); } /// /// Find the playstation ip /// public static string FindPlayStation() { UdpClient uc = new UdpClient(); IPEndPoint server = new IPEndPoint(IPAddress.Any, 0); uc.EnableBroadcast = true; uc.Client.ReceiveTimeout = 4000; byte[] magic = BitConverter.GetBytes(BROADCAST_MAGIC); IPAddress addr = null; IPHostEntry host = Dns.GetHostEntry(Dns.GetHostName()); foreach (IPAddress ip in host.AddressList) { if (ip.AddressFamily == AddressFamily.InterNetwork) { addr = ip; } } if (addr == null) { throw new Exception("libdbg broadcast error: could not get host ip"); } uc.Send(magic, magic.Length, new IPEndPoint(GetBroadcastAddress(addr, IPAddress.Parse("255.255.255.0")), BROADCAST_PORT)); byte[] resp = uc.Receive(ref server); if (BitConverter.ToUInt32(resp, 0) != BROADCAST_MAGIC) { throw new Exception("libdbg broadcast error: wrong magic on udp server"); } return server.Address.ToString(); } /// /// Connects to PlayStation 4 /// public void Connect() { if (!IsConnected) { sock.NoDelay = true; sock.ReceiveBufferSize = NET_MAX_LENGTH; sock.SendBufferSize = NET_MAX_LENGTH; sock.ReceiveTimeout = -1; IAsyncResult result = sock.BeginConnect(enp, null, null); result.AsyncWaitHandle.WaitOne(3000); IsConnected = sock.Connected; } } /// /// Disconnects from PlayStation 4 /// public void Disconnect() { SendCMDPacket(CMDS.CMD_CONSOLE_END, 0); sock.Shutdown(SocketShutdown.Both); sock.Close(); IsConnected = false; } /// /// Get current ps4debug version from library /// public string GetLibraryDebugVersion() { return LIBRARY_VERSION; } /// /// Get the current ps4debug version from console /// public string GetConsoleDebugVersion() { CheckConnected(); SendCMDPacket(CMDS.CMD_VERSION, 0); byte[] ldata = new byte[4]; sock.Receive(ldata, 4, SocketFlags.None); int length = BitConverter.ToInt32(ldata, 0); byte[] data = new byte[length]; sock.Receive(data, length, SocketFlags.None); return ConvertASCII(data, 0); } } } ================================================ FILE: libdebug/Process.cs ================================================ using System.Runtime.InteropServices; namespace libdebug { public class Process { public string name; public int pid; /// /// Initializes Process class /// /// Process name /// Process ID /// public Process(string name, int pid) { this.name = name; this.pid = pid; } public override string ToString() { return $"[{pid:X}] {name}"; } } public class ProcessList { public Process[] processes; /// /// Initializes ProcessList class /// /// Number of processes /// Process names /// Process IDs /// public ProcessList(int number, string[] names, int[] pids) { processes = new Process[number]; for (int i = 0; i < number; i++) { processes[i] = new Process(names[i], pids[i]); } } /// /// Finds a process based off name /// /// Process name /// Condition to check if process name contains name /// public Process FindProcess(string name, bool contains = false) { foreach (Process p in processes) { if (contains) { if (p.name.Contains(name)) { return p; } } else { if (p.name == name) { return p; } } } return null; } } public class MemoryEntry { public string name; public ulong start; public ulong end; public ulong offset; public uint prot; public override string ToString() { return $"{name} 0x{start:X}"; } } public class ProcessMap { public int pid; public MemoryEntry[] entries; /// /// Initializes ProcessMap class with memory entries and process ID /// /// Process ID /// Process memory entries /// public ProcessMap(int pid, MemoryEntry[] entries) { this.pid = pid; this.entries = entries; } /// /// Finds a virtual memory entry based off name /// /// Virtual memory entry name /// Condition to check if entry name contains name /// public MemoryEntry FindEntry(string name, bool contains = false) { foreach (MemoryEntry entry in entries) { if (contains) { if (entry.name.Contains(name)) { return entry; } } else { if (entry.name == name) { return entry; } } } return null; } /// /// Finds a virtual memory entry based off size /// /// Virtual memory entry size /// public MemoryEntry FindEntry(ulong size) { foreach (MemoryEntry entry in entries) { if ((entry.start - entry.end) == size) { return entry; } } return null; } } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] public struct ProcessInfo { public int pid; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 40)] public string name; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)] public string path; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)] public string titleid; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)] public string contentid; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] public struct ThreadInfo { public int pid; public int priority; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string name; } } ================================================ FILE: libdebug/Registers.cs ================================================ using System.Runtime.InteropServices; namespace libdebug { [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct regs { public ulong r_r15; public ulong r_r14; public ulong r_r13; public ulong r_r12; public ulong r_r11; public ulong r_r10; public ulong r_r9; public ulong r_r8; public ulong r_rdi; public ulong r_rsi; public ulong r_rbp; public ulong r_rbx; public ulong r_rdx; public ulong r_rcx; public ulong r_rax; public uint r_trapno; public ushort r_fs; public ushort r_gs; public uint r_err; public ushort r_es; public ushort r_ds; public ulong r_rip; public ulong r_cs; public ulong r_rflags; public ulong r_rsp; public ulong r_ss; } [StructLayout(LayoutKind.Sequential)] public struct envxmm { public ushort en_cw; /* control word (16bits) */ public ushort en_sw; /* status word (16bits) */ public byte en_tw; /* tag word (8bits) */ public byte en_zero; public ushort en_opcode; /* opcode last executed (11 bits ) */ public ulong en_rip; /* floating point instruction pointer */ public ulong en_rdp; /* floating operand pointer */ public uint en_mxcsr; /* SSE sontorol/status register */ public uint en_mxcsr_mask; /* valid bits in mxcsr */ } [StructLayout(LayoutKind.Sequential)] public struct acc { [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] public byte[] fp_bytes; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] private byte[] fp_pad; } [StructLayout(LayoutKind.Sequential)] public struct xmmacc { [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public byte[] xmm_bytes; } [StructLayout(LayoutKind.Sequential)] public struct ymmacc { [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public byte[] ymm_bytes; } [StructLayout(LayoutKind.Sequential)] public struct xstate_hdr { public ulong xstate_bv; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] private byte[] xstate_rsrv0; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)] private byte[] xstate_rsrv; } [StructLayout(LayoutKind.Sequential)] public struct savefpu_xstate { public xstate_hdr sx_hd; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public ymmacc[] sx_ymm; } [StructLayout(LayoutKind.Sequential, Pack = 64)] public struct fpregs { public envxmm svn_env; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public acc[] sv_fp; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public xmmacc[] sv_xmm; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 96)] private byte[] sv_pad; public savefpu_xstate sv_xstate; } [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct dbregs { public ulong dr0; public ulong dr1; public ulong dr2; public ulong dr3; public ulong dr4; public ulong dr5; public ulong dr6; public ulong dr7; public ulong dr8; public ulong dr9; public ulong dr10; public ulong dr11; public ulong dr12; public ulong dr13; public ulong dr14; public ulong dr15; } } ================================================ FILE: offsets.cs ================================================ using System; using System.Collections.Generic; using System.Text; namespace PS4Saves { class offsets { public const int sceUserServiceGetInitialUser = 0x33B0; public const int sceUserServiceGetLoginUserIdList = 0x2B40; public const int sceUserServiceGetUserName = 0x3F20; public const int sceSaveDataMount = 0x248D0; public const int sceSaveDataUmount = 0x250C0; public const int sceSaveDataDirNameSearch = 0x25CA0; public const int sceSaveDataInitialize3 = 0x24740; } } ================================================ FILE: structs.cs ================================================ using System.Runtime.InteropServices; namespace PS4Saves { [StructLayout(LayoutKind.Explicit, Size = 80)] public struct SceSaveDataMount { [FieldOffset(0x0)] public int userId; [FieldOffset(0x8)] public ulong titleId; [FieldOffset(0x10)] public ulong dirName; [FieldOffset(0x18)] public ulong fingerprint; [FieldOffset(0x20)] public ulong blocks; [FieldOffset(0x28)] public uint mountMode; } [StructLayout(LayoutKind.Explicit, Size = 64)] public struct SceSaveDataMount2 { [FieldOffset(0x0)] public int userId; [FieldOffset(0x8)] public ulong dirName; [FieldOffset(0x10)] public ulong blocks; [FieldOffset(0x18)] public uint mountMode; } [StructLayout(LayoutKind.Explicit, Size = 64)] public struct SceSaveDataMountResult { [FieldOffset(0x0)] public SceSaveDataMountPoint mountPoint; [FieldOffset(0x20)] public ulong requiredBlocks; [FieldOffset(0x28)] public uint mountStatus; } [StructLayout(LayoutKind.Sequential, Size = 16)] public struct SceSaveDataMountPoint { [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)] public string data; } [StructLayout(LayoutKind.Sequential, Size = 64)] public struct SceSaveDataTransferringMount { public int userId; public ulong titleId; public ulong dirName; public ulong fingerprint; } [StructLayout(LayoutKind.Sequential, Size = 16)] public struct SceSaveDataTitleId { [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)] public string data; } [StructLayout(LayoutKind.Sequential, Size = 32)] public struct SceSaveDataDirName { [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string data; } [StructLayout(LayoutKind.Sequential, Size = 80)] public struct SceSaveDataFingerprint { [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 65)] public string data; } [StructLayout(LayoutKind.Explicit, Size = 64)] public struct SceSaveDataDirNameSearchCond { [FieldOffset(0x0)] public int userId; [FieldOffset(0x8)] public ulong titleId; [FieldOffset(0x10)] public ulong dirName; [FieldOffset(0x18)] public uint key; [FieldOffset(0x1C)] public uint order; } [StructLayout(LayoutKind.Explicit, Size = 56)] public struct SceSaveDataDirNameSearchResult { [FieldOffset(0x0)] public uint hitNum; [FieldOffset(0x8)] public ulong dirNames; [FieldOffset(0x10)] public uint dirNamesNum; [FieldOffset(0x14)] public uint setNum; [FieldOffset(0x18)] public ulong param; [FieldOffset(0x20)] public ulong infos; } [StructLayout(LayoutKind.Explicit, Size = 1328)] public struct SceSaveDataParam { [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)] [FieldOffset(0x0)] public byte[] title; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)] [FieldOffset(0x80)] public byte[] subTitle; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1024)] [FieldOffset(0x100)] public byte[] detail; [FieldOffset(0x500)] public uint userParam; [FieldOffset(0x508)] public long mtime; } [StructLayout(LayoutKind.Sequential, Size = 48)] public struct SceSaveDataSearchInfo { public ulong blocks; public ulong freeBlocks; } }