├── .gitattributes ├── .gitignore ├── ArgAnalyzer.cs ├── CLegacyFunctions.cs ├── Program.cs ├── Properties └── launchSettings.json ├── README.md ├── WS2Script.cs ├── backup.txt ├── note_imgs ├── image-20230613194524700.png └── image-20230613194548453.png ├── ws2Parse.csproj └── ws2Parse.sln /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Ww][Ii][Nn]32/ 27 | [Aa][Rr][Mm]/ 28 | [Aa][Rr][Mm]64/ 29 | bld/ 30 | [Bb]in/ 31 | [Oo]bj/ 32 | [Oo]ut/ 33 | [Ll]og/ 34 | [Ll]ogs/ 35 | 36 | # Visual Studio 2015/2017 cache/options directory 37 | .vs/ 38 | # Uncomment if you have tasks that create the project's static files in wwwroot 39 | #wwwroot/ 40 | 41 | # Visual Studio 2017 auto generated files 42 | Generated\ Files/ 43 | 44 | # MSTest test Results 45 | [Tt]est[Rr]esult*/ 46 | [Bb]uild[Ll]og.* 47 | 48 | # NUnit 49 | *.VisualState.xml 50 | TestResult.xml 51 | nunit-*.xml 52 | 53 | # Build Results of an ATL Project 54 | [Dd]ebugPS/ 55 | [Rr]eleasePS/ 56 | dlldata.c 57 | 58 | # Benchmark Results 59 | BenchmarkDotNet.Artifacts/ 60 | 61 | # .NET Core 62 | project.lock.json 63 | project.fragment.lock.json 64 | artifacts/ 65 | 66 | # ASP.NET Scaffolding 67 | ScaffoldingReadMe.txt 68 | 69 | # StyleCop 70 | StyleCopReport.xml 71 | 72 | # Files built by Visual Studio 73 | *_i.c 74 | *_p.c 75 | *_h.h 76 | *.ilk 77 | *.meta 78 | *.obj 79 | *.iobj 80 | *.pch 81 | *.pdb 82 | *.ipdb 83 | *.pgc 84 | *.pgd 85 | *.rsp 86 | *.sbr 87 | *.tlb 88 | *.tli 89 | *.tlh 90 | *.tmp 91 | *.tmp_proj 92 | *_wpftmp.csproj 93 | *.log 94 | *.vspscc 95 | *.vssscc 96 | .builds 97 | *.pidb 98 | *.svclog 99 | *.scc 100 | 101 | # Chutzpah Test files 102 | _Chutzpah* 103 | 104 | # Visual C++ cache files 105 | ipch/ 106 | *.aps 107 | *.ncb 108 | *.opendb 109 | *.opensdf 110 | *.sdf 111 | *.cachefile 112 | *.VC.db 113 | *.VC.VC.opendb 114 | 115 | # Visual Studio profiler 116 | *.psess 117 | *.vsp 118 | *.vspx 119 | *.sap 120 | 121 | # Visual Studio Trace Files 122 | *.e2e 123 | 124 | # TFS 2012 Local Workspace 125 | $tf/ 126 | 127 | # Guidance Automation Toolkit 128 | *.gpState 129 | 130 | # ReSharper is a .NET coding add-in 131 | _ReSharper*/ 132 | *.[Rr]e[Ss]harper 133 | *.DotSettings.user 134 | 135 | # TeamCity is a build add-in 136 | _TeamCity* 137 | 138 | # DotCover is a Code Coverage Tool 139 | *.dotCover 140 | 141 | # AxoCover is a Code Coverage Tool 142 | .axoCover/* 143 | !.axoCover/settings.json 144 | 145 | # Coverlet is a free, cross platform Code Coverage Tool 146 | coverage*.json 147 | coverage*.xml 148 | coverage*.info 149 | 150 | # Visual Studio code coverage results 151 | *.coverage 152 | *.coveragexml 153 | 154 | # NCrunch 155 | _NCrunch_* 156 | .*crunch*.local.xml 157 | nCrunchTemp_* 158 | 159 | # MightyMoose 160 | *.mm.* 161 | AutoTest.Net/ 162 | 163 | # Web workbench (sass) 164 | .sass-cache/ 165 | 166 | # Installshield output folder 167 | [Ee]xpress/ 168 | 169 | # DocProject is a documentation generator add-in 170 | DocProject/buildhelp/ 171 | DocProject/Help/*.HxT 172 | DocProject/Help/*.HxC 173 | DocProject/Help/*.hhc 174 | DocProject/Help/*.hhk 175 | DocProject/Help/*.hhp 176 | DocProject/Help/Html2 177 | DocProject/Help/html 178 | 179 | # Click-Once directory 180 | publish/ 181 | 182 | # Publish Web Output 183 | *.[Pp]ublish.xml 184 | *.azurePubxml 185 | # Note: Comment the next line if you want to checkin your web deploy settings, 186 | # but database connection strings (with potential passwords) will be unencrypted 187 | *.pubxml 188 | *.publishproj 189 | 190 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 191 | # checkin your Azure Web App publish settings, but sensitive information contained 192 | # in these scripts will be unencrypted 193 | PublishScripts/ 194 | 195 | # NuGet Packages 196 | *.nupkg 197 | # NuGet Symbol Packages 198 | *.snupkg 199 | # The packages folder can be ignored because of Package Restore 200 | **/[Pp]ackages/* 201 | # except build/, which is used as an MSBuild target. 202 | !**/[Pp]ackages/build/ 203 | # Uncomment if necessary however generally it will be regenerated when needed 204 | #!**/[Pp]ackages/repositories.config 205 | # NuGet v3's project.json files produces more ignorable files 206 | *.nuget.props 207 | *.nuget.targets 208 | 209 | # Microsoft Azure Build Output 210 | csx/ 211 | *.build.csdef 212 | 213 | # Microsoft Azure Emulator 214 | ecf/ 215 | rcf/ 216 | 217 | # Windows Store app package directories and files 218 | AppPackages/ 219 | BundleArtifacts/ 220 | Package.StoreAssociation.xml 221 | _pkginfo.txt 222 | *.appx 223 | *.appxbundle 224 | *.appxupload 225 | 226 | # Visual Studio cache files 227 | # files ending in .cache can be ignored 228 | *.[Cc]ache 229 | # but keep track of directories ending in .cache 230 | !?*.[Cc]ache/ 231 | 232 | # Others 233 | ClientBin/ 234 | ~$* 235 | *~ 236 | *.dbmdl 237 | *.dbproj.schemaview 238 | *.jfm 239 | *.pfx 240 | *.publishsettings 241 | orleans.codegen.cs 242 | 243 | # Including strong name files can present a security risk 244 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 245 | #*.snk 246 | 247 | # Since there are multiple workflows, uncomment next line to ignore bower_components 248 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 249 | #bower_components/ 250 | 251 | # RIA/Silverlight projects 252 | Generated_Code/ 253 | 254 | # Backup & report files from converting an old project file 255 | # to a newer Visual Studio version. Backup files are not needed, 256 | # because we have git ;-) 257 | _UpgradeReport_Files/ 258 | Backup*/ 259 | UpgradeLog*.XML 260 | UpgradeLog*.htm 261 | ServiceFabricBackup/ 262 | *.rptproj.bak 263 | 264 | # SQL Server files 265 | *.mdf 266 | *.ldf 267 | *.ndf 268 | 269 | # Business Intelligence projects 270 | *.rdl.data 271 | *.bim.layout 272 | *.bim_*.settings 273 | *.rptproj.rsuser 274 | *- [Bb]ackup.rdl 275 | *- [Bb]ackup ([0-9]).rdl 276 | *- [Bb]ackup ([0-9][0-9]).rdl 277 | 278 | # Microsoft Fakes 279 | FakesAssemblies/ 280 | 281 | # GhostDoc plugin setting file 282 | *.GhostDoc.xml 283 | 284 | # Node.js Tools for Visual Studio 285 | .ntvs_analysis.dat 286 | node_modules/ 287 | 288 | # Visual Studio 6 build log 289 | *.plg 290 | 291 | # Visual Studio 6 workspace options file 292 | *.opt 293 | 294 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 295 | *.vbw 296 | 297 | # Visual Studio LightSwitch build output 298 | **/*.HTMLClient/GeneratedArtifacts 299 | **/*.DesktopClient/GeneratedArtifacts 300 | **/*.DesktopClient/ModelManifest.xml 301 | **/*.Server/GeneratedArtifacts 302 | **/*.Server/ModelManifest.xml 303 | _Pvt_Extensions 304 | 305 | # Paket dependency manager 306 | .paket/paket.exe 307 | paket-files/ 308 | 309 | # FAKE - F# Make 310 | .fake/ 311 | 312 | # CodeRush personal settings 313 | .cr/personal 314 | 315 | # Python Tools for Visual Studio (PTVS) 316 | __pycache__/ 317 | *.pyc 318 | 319 | # Cake - Uncomment if you are using it 320 | # tools/** 321 | # !tools/packages.config 322 | 323 | # Tabs Studio 324 | *.tss 325 | 326 | # Telerik's JustMock configuration file 327 | *.jmconfig 328 | 329 | # BizTalk build output 330 | *.btp.cs 331 | *.btm.cs 332 | *.odx.cs 333 | *.xsd.cs 334 | 335 | # OpenCover UI analysis results 336 | OpenCover/ 337 | 338 | # Azure Stream Analytics local run output 339 | ASALocalRun/ 340 | 341 | # MSBuild Binary and Structured Log 342 | *.binlog 343 | 344 | # NVidia Nsight GPU debugger configuration file 345 | *.nvuser 346 | 347 | # MFractors (Xamarin productivity tool) working folder 348 | .mfractor/ 349 | 350 | # Local History for Visual Studio 351 | .localhistory/ 352 | 353 | # BeatPulse healthcheck temp database 354 | healthchecksdb 355 | 356 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 357 | MigrationBackup/ 358 | 359 | # Ionide (cross platform F# VS Code tools) working folder 360 | .ionide/ 361 | 362 | # Fody - auto-generated XML schema 363 | FodyWeavers.xsd -------------------------------------------------------------------------------- /ArgAnalyzer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace ws2Parse 8 | { 9 | using System; 10 | using System.IO; 11 | using System.Data; 12 | using System.Collections; 13 | using System.Security.Cryptography; 14 | using ws2Parse.PE; 15 | using static ws2Parse.CLegacyFunctions; 16 | 17 | namespace PE 18 | { 19 | internal sealed class PeInfo 20 | { 21 | private DosHeader _DosHeader; 22 | private DosStub _DosStub; 23 | private PEHeader _PEHeader; 24 | private OptionalHeader _OptionalHeader; 25 | private OptionalDirAttrib _OptionalDirAttrib; 26 | private SectionTable _SectionTable; 27 | private byte[] _MountInfo; 28 | 29 | public PeInfo(string FileName) 30 | { 31 | using (FileStream fs = new FileStream(FileName, FileMode.Open)) 32 | using (BinaryReader br = new BinaryReader(fs)) 33 | { 34 | _DosHeader = new(br); 35 | int StubSize = (int)(Convert.ToInt32(_DosHeader.e_PESTART) - br.BaseStream.Position); //获得Stub的大小 36 | _DosStub = new(br, StubSize); 37 | _PEHeader = new(br); 38 | _OptionalHeader = new(br); 39 | _OptionalDirAttrib = new(br, _OptionalHeader.DirectCount); 40 | _SectionTable = new(br, _PEHeader.NumberOfSections); 41 | 42 | int MaxSize = 0; 43 | foreach (var v in _SectionTable.Sections) 44 | { 45 | if (v.VirtualAddress + v.SizeOfRawData > MaxSize) 46 | { 47 | MaxSize = v.VirtualAddress + v.SizeOfRawData; 48 | } 49 | } 50 | _MountInfo = new byte[MaxSize]; 51 | 52 | foreach (var sec in _SectionTable.Sections) 53 | { 54 | br.BaseStream.Position = sec.PointerToRawData; 55 | br.Read(_MountInfo, sec.VirtualAddress, sec.SizeOfRawData); 56 | } 57 | } 58 | } 59 | 60 | public int PatternSearch(byte[] bPattern) 61 | { 62 | int offset = 0; 63 | while(offset < _MountInfo.Length - bPattern.Length) 64 | { 65 | bool found = true; 66 | 67 | for (int i = 0; i < bPattern.Length; i++) 68 | { 69 | if (offset == _MountInfo.Length - i) 70 | { 71 | found = false; 72 | break; 73 | } 74 | 75 | if (bPattern[i] != 0x2A && bPattern[i] != _MountInfo[offset + i]) 76 | { 77 | found = false; 78 | break; 79 | } 80 | } 81 | 82 | if (found) 83 | { 84 | return offset; 85 | } 86 | 87 | offset++; 88 | } 89 | return -1; 90 | } 91 | 92 | public int GetRVA32(int offset) 93 | { 94 | var addr = BitConverter.ToInt32(_MountInfo, offset); 95 | if (addr == 0) 96 | return 0; 97 | return addr - 0x400000; 98 | } 99 | 100 | public int GetInt32(int offset) 101 | { 102 | return BitConverter.ToInt32(_MountInfo, offset); 103 | } 104 | 105 | public byte GetByte(int offset) 106 | { 107 | return _MountInfo[offset]; 108 | } 109 | 110 | private class DosHeader 111 | { 112 | public byte[] e_magic; // 魔术数字 113 | public byte[] e_cblp; // 文件最后页的字节数 114 | public byte[] e_cp; // 文件页数 115 | public byte[] e_crlc; // 重定义元素个数 116 | public byte[] e_cparhdr; // 头部尺寸,以段落为单位 117 | public byte[] e_minalloc; // 所需的最小附加段 118 | public byte[] e_maxalloc; // 所需的最大附加段 119 | public byte[] e_ss; // 初始的SS值(相对偏移量) 120 | public byte[] e_sp; // 初始的SP值 121 | public byte[] e_csum; // 校验和 122 | public byte[] e_ip; // 初始的IP值 123 | public byte[] e_cs; // 初始的CS值(相对偏移量) 124 | public byte[] e_rva; 125 | public byte[] e_fg; 126 | public byte[] e_bl1; 127 | public byte[] e_oemid; 128 | public byte[] e_oeminfo; 129 | public byte[] e_bl2; 130 | public short e_PESTART; //PE开始 +自己的位置 131 | 132 | 133 | public long FileStarIndex = 0; 134 | public long FileEndIndex = 0; 135 | 136 | public DosHeader(BinaryReader br) 137 | { 138 | FileStarIndex = br.BaseStream.Position; 139 | e_magic = br.ReadBytes(2); 140 | e_cblp = br.ReadBytes(2); 141 | e_cp = br.ReadBytes(2); 142 | e_crlc = br.ReadBytes(2); 143 | e_cparhdr = br.ReadBytes(2); 144 | e_minalloc = br.ReadBytes(2); 145 | e_maxalloc = br.ReadBytes(2); 146 | e_ss = br.ReadBytes(2); 147 | e_sp = br.ReadBytes(2); 148 | e_csum = br.ReadBytes(2); 149 | e_ip = br.ReadBytes(2); 150 | e_cs = br.ReadBytes(2); 151 | e_rva = br.ReadBytes(2); 152 | e_fg = br.ReadBytes(2); 153 | e_bl1 = br.ReadBytes(8); 154 | e_oemid = br.ReadBytes(2); 155 | e_oeminfo = br.ReadBytes(2); 156 | e_bl2 = br.ReadBytes(20); 157 | e_PESTART = br.ReadInt16(); 158 | FileEndIndex = br.BaseStream.Position; 159 | } 160 | } 161 | 162 | private class DosStub 163 | { 164 | public byte[] DosStubData; 165 | public long FileStarIndex = 0; 166 | public long FileEndIndex = 0; 167 | 168 | 169 | public DosStub(BinaryReader br, int StubSize) 170 | { 171 | FileStarIndex = br.BaseStream.Position; 172 | DosStubData = br.ReadBytes(StubSize); 173 | FileEndIndex = br.BaseStream.Position; 174 | } 175 | } 176 | 177 | private class PEHeader 178 | { 179 | public byte[] Header; //PE文件标记 180 | public byte[] Machine;//该文件运行所要求的CPU。对于Intel平台,该值是IMAGE_FILE_MACHINE_I386 (14Ch)。我们尝试了LUEVELSMEYER的pe.txt声明的14Dh和14Eh,但Windows不能正确执行。看起来,除了禁止程序执行之外,本域对我们来说用处不大。 181 | public short NumberOfSections;//文件的节数目。如果我们要在文件中增加或删除一个节,就需要修改这个值。 182 | public byte[] TimeDateStamp;//文件创建日期和时间。我们不感兴趣。 183 | public byte[] PointerToSymbolTable;//用于调试。 184 | public byte[] NumberOfSymbols;//用于调试。 185 | public byte[] SizeOfOptionalHeader;//指示紧随本结构之后的 OptionalHeader 结构大小,必须为有效值。 186 | public byte[] Characteristics;//关于文件信息的标记,比如文件是exe还是dll。 187 | 188 | public long FileStarIndex = 0; 189 | public long FileEndIndex = 0; 190 | 191 | public PEHeader(BinaryReader br) 192 | { 193 | FileStarIndex = br.BaseStream.Position; 194 | Header = br.ReadBytes(4); 195 | Machine = br.ReadBytes(2); 196 | NumberOfSections = br.ReadInt16(); 197 | TimeDateStamp = br.ReadBytes(4); 198 | PointerToSymbolTable = br.ReadBytes(4); 199 | NumberOfSymbols = br.ReadBytes(4); 200 | SizeOfOptionalHeader = br.ReadBytes(2); 201 | Characteristics = br.ReadBytes(2); 202 | FileEndIndex = br.BaseStream.Position; 203 | } 204 | } 205 | 206 | private class OptionalHeader 207 | { 208 | public byte[] Magic; //Magic 010B=普通可以执行,0107=ROM映像 209 | public byte[] MajorLinkerVersion; //主版本号 210 | public byte[] MinorLinkerVersion; //副版本号 211 | public byte[] SizeOfCode; //代码段大小 212 | public byte[] SizeOfInitializedData; //已初始化数据大小 213 | public byte[] SizeOfUninitializedData; //未初始化数据大小 214 | public byte[] AddressOfEntryPoint; //执行将从这里开始(RVA) 215 | public byte[] BaseOfCode; //代码基址(RVA) 216 | public byte[] ImageBase; //数据基址(RVA) 217 | public byte[] ImageFileCode; //映象文件基址 218 | public byte[] SectionAlign; //区段列队 219 | public byte[] FileAlign; //文件列队 220 | 221 | public byte[] MajorOSV; //操作系统主版本号 222 | public byte[] MinorOSV; //操作系统副版本号 223 | public byte[] MajorImageVer; //映象文件主版本号 224 | public byte[] MinorImageVer; //映象文件副版本号 225 | public byte[] MajorSV; //子操作系统主版本号 226 | public byte[] MinorSV; //子操作系统副版本号 227 | public byte[] UNKNOW; //Win32版本值 228 | public byte[] SizeOfImage; //映象文件大小 229 | public byte[] SizeOfHeards; //标志头大小 230 | public byte[] CheckSum; //文件效验 231 | public byte[] Subsystem;//子系统(映象文件)1本地 2WINDOWS-GUI 3WINDOWS-CUI 4 POSIX-CUI 232 | public byte[] DLL_Characteristics;//DLL标记 233 | public byte[] Bsize; //保留栈的大小 234 | public byte[] TimeBsize; //初始时指定栈大小 235 | public byte[] AucBsize; //保留堆的大小 236 | public byte[] SizeOfBsize; //初始时指定堆大小 237 | public byte[] FuckBsize; //加载器标志 238 | public int DirectCount; //数据目录数 239 | 240 | public long FileStarIndex = 0; 241 | public long FileEndIndex = 0; 242 | 243 | public OptionalHeader(BinaryReader br) 244 | { 245 | FileStarIndex = br.BaseStream.Position; 246 | Magic = br.ReadBytes(2); 247 | MajorLinkerVersion = br.ReadBytes(1); 248 | MinorLinkerVersion = br.ReadBytes(1); 249 | SizeOfCode = br.ReadBytes(4); 250 | SizeOfInitializedData = br.ReadBytes(4); 251 | SizeOfUninitializedData = br.ReadBytes(4); 252 | AddressOfEntryPoint = br.ReadBytes(4); 253 | BaseOfCode = br.ReadBytes(4); 254 | ImageBase = br.ReadBytes(4); 255 | ImageFileCode = br.ReadBytes(4); 256 | SectionAlign = br.ReadBytes(4); 257 | FileAlign = br.ReadBytes(4); 258 | 259 | MajorOSV = br.ReadBytes(2); 260 | MinorOSV = br.ReadBytes(2); 261 | MajorImageVer = br.ReadBytes(2); 262 | MinorImageVer = br.ReadBytes(2); 263 | MajorSV = br.ReadBytes(2); 264 | MinorSV = br.ReadBytes(2); 265 | UNKNOW = br.ReadBytes(4); 266 | SizeOfImage = br.ReadBytes(4); 267 | SizeOfHeards = br.ReadBytes(4); 268 | CheckSum = br.ReadBytes(4); 269 | Subsystem = br.ReadBytes(2); 270 | DLL_Characteristics = br.ReadBytes(2); 271 | Bsize = br.ReadBytes(4); 272 | TimeBsize = br.ReadBytes(4); 273 | AucBsize = br.ReadBytes(4); 274 | SizeOfBsize = br.ReadBytes(4); 275 | FuckBsize = br.ReadBytes(4); 276 | DirectCount = br.ReadInt32(); 277 | 278 | FileEndIndex = br.BaseStream.Position; 279 | } 280 | } 281 | 282 | private class OptionalDirAttrib 283 | { 284 | public class DirAttrib 285 | { 286 | public int DirRva; //地址 287 | public int DirSize; //大小 288 | 289 | public DirAttrib(BinaryReader br) 290 | { 291 | DirRva = br.ReadInt32(); 292 | DirSize = br.ReadInt32(); 293 | } 294 | } 295 | 296 | public List DirByte; 297 | 298 | 299 | 300 | public long FileStarIndex = 0; 301 | public long FileEndIndex = 0; 302 | 303 | public OptionalDirAttrib(BinaryReader br, int count) 304 | { 305 | FileStarIndex = br.BaseStream.Position; 306 | 307 | DirByte = new(); 308 | for (int i = 0; i < count; i++) 309 | { 310 | DirByte.Add(new DirAttrib(br)); 311 | } 312 | 313 | FileEndIndex = br.BaseStream.Position; 314 | } 315 | } 316 | 317 | private class SectionTable 318 | { 319 | public class SectionData 320 | { 321 | public string SectName; //名字 322 | public int PhysicalAddress; //虚拟内存地址 323 | public int VirtualAddress; //RVA偏移 324 | public int SizeOfRawData; //RVA大小 325 | public int PointerToRawData; //指向RAW数据 326 | public int PointerToRelocations; //指向定位号 327 | public int PointerToLinenumbers; //指向行数 328 | public short NumberOfRelocations; //定位号 329 | public short NumberOfLinenumbers; //行数号 330 | public int Characteristics; //区段标记 331 | 332 | public SectionData(BinaryReader br) 333 | { 334 | SectName = Encoding.ASCII.GetString(br.ReadBytes(8)); 335 | PhysicalAddress = br.ReadInt32(); 336 | VirtualAddress = br.ReadInt32(); 337 | SizeOfRawData = br.ReadInt32(); 338 | PointerToRawData = br.ReadInt32(); 339 | PointerToRelocations = br.ReadInt32(); 340 | PointerToLinenumbers = br.ReadInt32(); 341 | NumberOfRelocations = br.ReadInt16(); 342 | NumberOfLinenumbers = br.ReadInt16(); 343 | Characteristics = br.ReadInt32(); 344 | } 345 | } 346 | public List Sections; 347 | 348 | public long FileStarIndex = 0; 349 | public long FileEndIndex = 0; 350 | 351 | public SectionTable(BinaryReader br, int count) 352 | { 353 | FileStarIndex = br.BaseStream.Position; 354 | Sections = new(); 355 | for (int i = 0; i < count; i++) 356 | { 357 | Sections.Add(new SectionData(br)); 358 | } 359 | FileEndIndex = br.BaseStream.Position; 360 | } 361 | } 362 | } 363 | 364 | public static class ArgAnalyzer 365 | { 366 | private static int GetOffset(PeInfo info) 367 | { 368 | int offset; 369 | //1056&1210 370 | offset = info.PatternSearch(new byte[] { 0x8B, 0x2C, 0x85, 0x2A, 0x2A, 0x2A, 0x2A, 0x85, 0xED }); 371 | if (offset != -1) 372 | return offset + 3; 373 | //1994 374 | offset = info.PatternSearch(new byte[] { 0x8B, 0x1C, 0x85, 0x2A, 0x2A, 0x2A, 0x2A, 0x85, 0xDB, 0x75, 0x1F }); 375 | if (offset != -1) 376 | return offset + 3; 377 | //1996 378 | offset = info.PatternSearch(new byte[] { 0x8B, 0x04, 0x85, 0x2A, 0x2A, 0x2A, 0x2A, 0x89, 0x45, 0xE4 }); 379 | if (offset != -1) 380 | return offset + 3; 381 | //1999 382 | offset = info.PatternSearch(new byte[] { 0x8B, 0x0C, 0x8D, 0x2A, 0x2A, 0x2A, 0x2A, 0x89, 0x4D, 0xDC, 0x85, 0xC9 }); 383 | if (offset != -1) 384 | return offset + 3; 385 | //19910 386 | offset = info.PatternSearch(new byte[] { 0x8B, 0x04, 0x85, 0x2A, 0x2A, 0x2A, 0x2A, 0x89, 0x45, 0xF0, 0x85, 0xC0 }); 387 | if (offset != -1) 388 | return offset + 3; 389 | return 0; 390 | } 391 | 392 | public static ArgTypes[][] ExtractArgTypes(string exePath) 393 | { 394 | PeInfo pf = new(exePath); 395 | int offset = GetOffset(pf); 396 | if (offset == 0) 397 | return Array.Empty(); 398 | 399 | int val = pf.GetRVA32(offset); 400 | 401 | List argTypes = new List(); 402 | int curOffset; 403 | for(int i = 0; i<256; i++) 404 | { 405 | curOffset = pf.GetRVA32(val); 406 | 407 | if (curOffset != 0) 408 | { 409 | List typeList = new List(); 410 | bool isArgEnd; 411 | 412 | do{ 413 | var type = (ArgTypes)pf.GetByte(curOffset); 414 | curOffset++; 415 | typeList.Add(type); 416 | isArgEnd = type == ArgTypes.ARG_END; 417 | } 418 | while(!isArgEnd); 419 | 420 | argTypes.Add(typeList.ToArray()); 421 | } 422 | else 423 | { 424 | argTypes.Add(Array.Empty()); 425 | } 426 | 427 | val += 4; 428 | } 429 | 430 | return argTypes.ToArray(); 431 | } 432 | } 433 | } 434 | 435 | } -------------------------------------------------------------------------------- /CLegacyFunctions.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using ws2Parse.PE; 9 | 10 | namespace ws2Parse 11 | { 12 | public static class CLegacyFunctions 13 | { 14 | static readonly Encoding read_encoding = Encoding.GetEncoding("shift_jis"); 15 | static readonly Encoding write_encoding = Encoding.GetEncoding("gbk"); 16 | public class Arg 17 | { 18 | public string type; 19 | ArgTypes etype; 20 | public object data; 21 | 22 | public Arg(ArgTypes type, object data) 23 | { 24 | etype = type; 25 | this.type = type.ToString(); 26 | this.data = data; 27 | } 28 | 29 | public Arg(ArgTypes type, int count, object data) 30 | { 31 | etype = type; 32 | this.type = string.Format("{0}[{1}]", type.ToString(), count); ; 33 | this.data = data; 34 | } 35 | 36 | public ArgTypes GetArgType() 37 | { 38 | return etype; 39 | } 40 | } 41 | 42 | public class CommandOffset 43 | { 44 | public uint old; 45 | public uint cur; 46 | } 47 | 48 | public class Command 49 | { 50 | public CommandOffset offset; 51 | public byte op; 52 | public string name; 53 | public List args; 54 | 55 | public Command(ref int veip, byte op, byte[] script) 56 | { 57 | offset = new CommandOffset(); 58 | offset.old = (uint)veip - 1; 59 | offset.cur = 0; 60 | this.op = op; 61 | name = GetFunctionName(op, veip - 1); 62 | args = ReadArgs(op, script, ref veip); 63 | } 64 | 65 | public Command(ref int veip, byte op) 66 | { 67 | offset = new CommandOffset(); 68 | offset.old = (uint)veip - 1; 69 | offset.cur = 0; 70 | this.op = op; 71 | args = new List(); 72 | name = "End of Script"; 73 | } 74 | 75 | public byte[] GetBytes() 76 | { 77 | var ret = new List(); 78 | ret.Add(op); 79 | ret.AddRange(WriteArgs(args)); 80 | return ret.ToArray(); 81 | } 82 | } 83 | 84 | public enum ArgTypes 85 | { 86 | ARG_VT_UI1 = 0, 87 | ARG_VT_I2 = 1, 88 | ARG_VT_UI2 = 2, 89 | ARG_VT_INT = 3, 90 | ARG_VT_UI4 = 4, 91 | ARG_VT_R4 = 5, 92 | ARG_STR1 = 6, 93 | ARG_ARRAY = 7, 94 | ARG_PERIOD = 8, 95 | ARG_STR2 = 9, 96 | ARG_STR3 = 0x0A, 97 | //ARG_UTF8STR = 0x0B, 98 | ARG_CALLBACK = 0xFE, 99 | ARG_END = 0xFF 100 | } 101 | 102 | static ArgTypes[][] func_args = new ArgTypes[256][] 103 | { 104 | //For AdvHD ver 1.2.1.0 105 | new ArgTypes[]{ ArgTypes.ARG_END }, 106 | new ArgTypes[]{ ArgTypes.ARG_VT_UI1, ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_UI4, ArgTypes.ARG_VT_UI4, ArgTypes.ARG_END },//JX 107 | new ArgTypes[]{ ArgTypes.ARG_VT_UI4, ArgTypes.ARG_END },//JMP 108 | Array.Empty(), 109 | new ArgTypes[]{ ArgTypes.ARG_STR3, ArgTypes.ARG_PERIOD, ArgTypes.ARG_END }, 110 | new ArgTypes[]{ ArgTypes.ARG_END }, 111 | new ArgTypes[]{ ArgTypes.ARG_VT_UI4, ArgTypes.ARG_END },//JMP 112 | new ArgTypes[]{ ArgTypes.ARG_STR3, ArgTypes.ARG_PERIOD, ArgTypes.ARG_END }, 113 | new ArgTypes[]{ ArgTypes.ARG_VT_UI1, ArgTypes.ARG_END }, 114 | new ArgTypes[]{ ArgTypes.ARG_VT_UI1, ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_R4, ArgTypes.ARG_END }, 115 | new ArgTypes[]{ ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_R4, ArgTypes.ARG_END }, 116 | new ArgTypes[]{ ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_END }, 117 | new ArgTypes[]{ ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_ARRAY, ArgTypes.ARG_VT_I2, ArgTypes.ARG_END }, 118 | new ArgTypes[]{ ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_R4, ArgTypes.ARG_END }, 119 | new ArgTypes[]{ ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_END }, 120 | new ArgTypes[]{ ArgTypes.ARG_VT_UI1, ArgTypes.ARG_END }, 121 | Array.Empty(), 122 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_R4, ArgTypes.ARG_END }, 123 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_STR3, ArgTypes.ARG_PERIOD, ArgTypes.ARG_END }, 124 | new ArgTypes[]{ ArgTypes.ARG_END }, 125 | new ArgTypes[]{ ArgTypes.ARG_VT_UI4, ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_END }, 126 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_END }, 127 | new ArgTypes[]{ ArgTypes.ARG_VT_UI1, ArgTypes.ARG_END }, 128 | new ArgTypes[]{ ArgTypes.ARG_END }, 129 | new ArgTypes[]{ ArgTypes.ARG_VT_UI1, ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_END }, 130 | new ArgTypes[]{ ArgTypes.ARG_END }, 131 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_END }, 132 | new ArgTypes[]{ ArgTypes.ARG_VT_UI1, ArgTypes.ARG_END }, 133 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_END }, 134 | new ArgTypes[]{ ArgTypes.ARG_VT_I2, ArgTypes.ARG_END }, 135 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR3, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_END }, 136 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_R4, ArgTypes.ARG_END }, 137 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_I2, ArgTypes.ARG_END }, 138 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_I2, ArgTypes.ARG_END }, 139 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_END }, 140 | Array.Empty(), 141 | Array.Empty(), 142 | Array.Empty(), 143 | Array.Empty(), 144 | Array.Empty(), 145 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR3, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_END }, 146 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_R4, ArgTypes.ARG_END }, 147 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_I2, ArgTypes.ARG_END }, 148 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_END }, 149 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_END }, 150 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_END }, 151 | new ArgTypes[]{ ArgTypes.ARG_END }, 152 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_R4, ArgTypes.ARG_END }, 153 | Array.Empty(), 154 | Array.Empty(), 155 | new ArgTypes[]{ ArgTypes.ARG_STR3, ArgTypes.ARG_PERIOD, ArgTypes.ARG_END }, 156 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR3, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_END }, 157 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR3, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_END }, 158 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR3, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_END }, 159 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_END }, 160 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_END }, 161 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_END }, 162 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_ARRAY, ArgTypes.ARG_VT_I2, ArgTypes.ARG_END }, 163 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_END }, 164 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_END }, 165 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_END }, 166 | new ArgTypes[]{ ArgTypes.ARG_VT_I2, ArgTypes.ARG_END }, 167 | new ArgTypes[]{ ArgTypes.ARG_END }, 168 | new ArgTypes[]{ ArgTypes.ARG_ARRAY, ArgTypes.ARG_STR1, ArgTypes.ARG_END },//string arr 169 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR3, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_END }, 170 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_END }, 171 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_I2, ArgTypes.ARG_END }, 172 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_END }, 173 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_END }, 174 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_END }, 175 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_END }, 176 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_R4, ArgTypes.ARG_END }, 177 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_STR3, ArgTypes.ARG_PERIOD, ArgTypes.ARG_END }, 178 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR3, ArgTypes.ARG_PERIOD, ArgTypes.ARG_END }, 179 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_END }, 180 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_END }, 181 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_END }, 182 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_R4, ArgTypes.ARG_END }, 183 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_STR3, ArgTypes.ARG_PERIOD, ArgTypes.ARG_END }, 184 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_I2, ArgTypes.ARG_STR3, ArgTypes.ARG_PERIOD, ArgTypes.ARG_END }, 185 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_I2, ArgTypes.ARG_END }, 186 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_END }, 187 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_STR3, ArgTypes.ARG_PERIOD, ArgTypes.ARG_END }, 188 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_END }, 189 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR3, ArgTypes.ARG_PERIOD, ArgTypes.ARG_END }, 190 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_END }, 191 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_VT_I2, ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_I2, ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR3, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_R4, ArgTypes.ARG_END }, 192 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_I2, ArgTypes.ARG_END }, 193 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_END }, 194 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_I2, ArgTypes.ARG_END }, 195 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_ARRAY, ArgTypes.ARG_VT_I2, ArgTypes.ARG_END }, 196 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_END }, 197 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_END }, 198 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_UI1,ArgTypes.ARG_END }, 199 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_END }, 200 | Array.Empty(), 201 | Array.Empty(), 202 | Array.Empty(), 203 | Array.Empty(), 204 | Array.Empty(), 205 | new ArgTypes[]{ ArgTypes.ARG_VT_UI1, ArgTypes.ARG_END }, 206 | new ArgTypes[]{ ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_STR3, ArgTypes.ARG_PERIOD, ArgTypes.ARG_END }, 207 | new ArgTypes[]{ ArgTypes.ARG_STR3, ArgTypes.ARG_PERIOD, ArgTypes.ARG_END }, 208 | new ArgTypes[]{ ArgTypes.ARG_VT_UI1, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_END }, 209 | new ArgTypes[]{ ArgTypes.ARG_VT_UI1, ArgTypes.ARG_END }, 210 | Array.Empty(), 211 | Array.Empty(), 212 | Array.Empty(), 213 | Array.Empty(), 214 | Array.Empty(), 215 | new ArgTypes[]{ ArgTypes.ARG_STR2, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR2, ArgTypes.ARG_PERIOD, ArgTypes.ARG_END }, 216 | new ArgTypes[]{ ArgTypes.ARG_STR2, ArgTypes.ARG_PERIOD, ArgTypes.ARG_END }, 217 | new ArgTypes[]{ ArgTypes.ARG_STR2, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_I2, ArgTypes.ARG_END }, 218 | new ArgTypes[]{ ArgTypes.ARG_END }, 219 | new ArgTypes[]{ ArgTypes.ARG_STR2, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_I2, ArgTypes.ARG_STR2, ArgTypes.ARG_PERIOD, ArgTypes.ARG_END }, 220 | new ArgTypes[]{ ArgTypes.ARG_STR2, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR2, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_I2, ArgTypes.ARG_END }, 221 | new ArgTypes[]{ ArgTypes.ARG_STR2, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR2, ArgTypes.ARG_PERIOD, ArgTypes.ARG_END }, 222 | new ArgTypes[]{ ArgTypes.ARG_STR2, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_END }, 223 | Array.Empty(), 224 | Array.Empty(), 225 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR3, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_END }, 226 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_R4, ArgTypes.ARG_END }, 227 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR3, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_STR3, ArgTypes.ARG_PERIOD, ArgTypes.ARG_END }, 228 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR3, ArgTypes.ARG_PERIOD, ArgTypes.ARG_END }, 229 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_R4, ArgTypes.ARG_END }, 230 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_R4, ArgTypes.ARG_END }, 231 | new ArgTypes[]{ ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_END }, 232 | #region unused 233 | Array.Empty(), 234 | Array.Empty(), 235 | Array.Empty(), 236 | Array.Empty(), 237 | Array.Empty(), 238 | Array.Empty(), 239 | Array.Empty(), 240 | Array.Empty(), 241 | Array.Empty(), 242 | Array.Empty(), 243 | Array.Empty(), 244 | Array.Empty(), 245 | Array.Empty(), 246 | Array.Empty(), 247 | Array.Empty(), 248 | Array.Empty(), 249 | Array.Empty(), 250 | Array.Empty(), 251 | Array.Empty(), 252 | Array.Empty(), 253 | Array.Empty(), 254 | Array.Empty(), 255 | Array.Empty(), 256 | Array.Empty(), 257 | Array.Empty(), 258 | Array.Empty(), 259 | Array.Empty(), 260 | Array.Empty(), 261 | Array.Empty(), 262 | Array.Empty(), 263 | Array.Empty(), 264 | Array.Empty(), 265 | Array.Empty(), 266 | Array.Empty(), 267 | Array.Empty(), 268 | Array.Empty(), 269 | Array.Empty(), 270 | Array.Empty(), 271 | Array.Empty(), 272 | Array.Empty(), 273 | Array.Empty(), 274 | Array.Empty(), 275 | Array.Empty(), 276 | Array.Empty(), 277 | Array.Empty(), 278 | Array.Empty(), 279 | Array.Empty(), 280 | Array.Empty(), 281 | Array.Empty(), 282 | Array.Empty(), 283 | Array.Empty(), 284 | Array.Empty(), 285 | Array.Empty(), 286 | Array.Empty(), 287 | Array.Empty(), 288 | Array.Empty(), 289 | Array.Empty(), 290 | Array.Empty(), 291 | Array.Empty(), 292 | Array.Empty(), 293 | Array.Empty(), 294 | Array.Empty(), 295 | Array.Empty(), 296 | Array.Empty(), 297 | Array.Empty(), 298 | Array.Empty(), 299 | Array.Empty(), 300 | Array.Empty(), 301 | Array.Empty(), 302 | Array.Empty(), 303 | Array.Empty(), 304 | Array.Empty(), 305 | Array.Empty(), 306 | Array.Empty(), 307 | Array.Empty(), 308 | Array.Empty(), 309 | Array.Empty(), 310 | Array.Empty(), 311 | Array.Empty(), 312 | Array.Empty(), 313 | Array.Empty(), 314 | Array.Empty(), 315 | Array.Empty(), 316 | Array.Empty(), 317 | Array.Empty(), 318 | Array.Empty(), 319 | Array.Empty(), 320 | Array.Empty(), 321 | Array.Empty(), 322 | Array.Empty(), 323 | Array.Empty(), 324 | Array.Empty(), 325 | Array.Empty(), 326 | Array.Empty(), 327 | Array.Empty(), 328 | Array.Empty(), 329 | Array.Empty(), 330 | Array.Empty(), 331 | Array.Empty(), 332 | Array.Empty(), 333 | Array.Empty(), 334 | Array.Empty(), 335 | Array.Empty(), 336 | Array.Empty(), 337 | Array.Empty(), 338 | Array.Empty(), 339 | Array.Empty(), 340 | Array.Empty(), 341 | Array.Empty(), 342 | Array.Empty(), 343 | Array.Empty(), 344 | Array.Empty(), 345 | Array.Empty(), 346 | Array.Empty(), 347 | Array.Empty(), 348 | Array.Empty(), 349 | Array.Empty(), 350 | Array.Empty(), 351 | Array.Empty(), 352 | Array.Empty(), 353 | Array.Empty(), 354 | #endregion unused 355 | new ArgTypes[] { ArgTypes.ARG_END }, 356 | new ArgTypes[] { ArgTypes.ARG_VT_UI1, ArgTypes.ARG_STR3, ArgTypes.ARG_PERIOD, ArgTypes.ARG_END }, 357 | new ArgTypes[] { ArgTypes.ARG_END }, 358 | new ArgTypes[] { ArgTypes.ARG_VT_UI1, ArgTypes.ARG_END }, 359 | new ArgTypes[] { ArgTypes.ARG_VT_I2, ArgTypes.ARG_END }, 360 | new ArgTypes[] { ArgTypes.ARG_END }, 361 | new ArgTypes[] { ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_END }, 362 | Array.Empty()//ScriptEnd 363 | }; 364 | 365 | public static void UpdateVM1993() 366 | { 367 | //AdvHD ver 1.9.9.3 updated VM Functions 368 | func_args[17] = new ArgTypes[] { ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_VT_R4, ArgTypes.ARG_END }; 369 | func_args[20] = new ArgTypes[] { ArgTypes.ARG_VT_UI4, ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_END }; 370 | func_args[21] = new ArgTypes[] { ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_END }; 371 | func_args[22] = new ArgTypes[] { ArgTypes.ARG_VT_UI1, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_END }; 372 | func_args[30] = new ArgTypes[] { ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR3, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_VT_R4, ArgTypes.ARG_END }; 373 | func_args[40] = new ArgTypes[] { ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR3, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_VT_R4, ArgTypes.ARG_END }; 374 | func_args[95] = new ArgTypes[] { ArgTypes.ARG_STR3, ArgTypes.ARG_PERIOD, ArgTypes.ARG_END }; 375 | func_args[96] = new ArgTypes[] { ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_I2, ArgTypes.ARG_END }; 376 | func_args[97] = new ArgTypes[] { ArgTypes.ARG_VT_UI1, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_END }; 377 | func_args[98] = new ArgTypes[] { ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_END }; 378 | func_args[99] = new ArgTypes[] { ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_END }; 379 | func_args[105] = new ArgTypes[] { ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_R4, ArgTypes.ARG_END }; 380 | func_args[106] = new ArgTypes[] { ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_STR3, ArgTypes.ARG_PERIOD, ArgTypes.ARG_END }; 381 | func_args[107] = new ArgTypes[] { ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_END }; 382 | func_args[108] = new ArgTypes[] { ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_END }; 383 | func_args[110] = new ArgTypes[] { ArgTypes.ARG_STR2, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_END }; 384 | func_args[120] = new ArgTypes[] { ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR3, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_END }; 385 | func_args[127] = new ArgTypes[] { ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_END }; 386 | func_args[128] = new ArgTypes[] { ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_END }; 387 | func_args[129] = new ArgTypes[] { ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_STR3, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_END }; 388 | func_args[130] = new ArgTypes[] { ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR3, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_R4, ArgTypes.ARG_END }; 389 | func_args[131] = new ArgTypes[] { ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_END }; 390 | func_args[132] = new ArgTypes[] { ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_R4, ArgTypes.ARG_END }; 391 | func_args[133] = new ArgTypes[] { ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_VT_R4, ArgTypes.ARG_END }; 392 | func_args[134] = new ArgTypes[] { ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_END }; 393 | func_args[135] = new ArgTypes[] { ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_R4, ArgTypes.ARG_END }; 394 | func_args[136] = new ArgTypes[] { ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_R4, ArgTypes.ARG_END }; 395 | func_args[140] = new ArgTypes[] { ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR3, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_END }; 396 | func_args[141] = new ArgTypes[] { ArgTypes.ARG_VT_UI4, ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_STR3, ArgTypes.ARG_PERIOD, ArgTypes.ARG_END }; 397 | func_args[142] = new ArgTypes[] { ArgTypes.ARG_VT_UI4, ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_STR3, ArgTypes.ARG_PERIOD, ArgTypes.ARG_END }; 398 | func_args[143] = new ArgTypes[] { ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR3, ArgTypes.ARG_PERIOD, ArgTypes.ARG_END }; 399 | func_args[144] = new ArgTypes[] { ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_END }; 400 | func_args[150] = new ArgTypes[] { ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_END }; 401 | func_args[151] = new ArgTypes[] { ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_END }; 402 | func_args[152] = new ArgTypes[] { ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_R4, ArgTypes.ARG_END }; 403 | func_args[153] = new ArgTypes[] { ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_STR3, ArgTypes.ARG_PERIOD, ArgTypes.ARG_END }; 404 | func_args[154] = new ArgTypes[] { ArgTypes.ARG_END }; 405 | func_args[155] = new ArgTypes[] { ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_END }; 406 | func_args[156] = new ArgTypes[] { ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR3, ArgTypes.ARG_PERIOD, ArgTypes.ARG_END }; 407 | func_args[157] = new ArgTypes[] { ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_END }; 408 | func_args[158] = new ArgTypes[] { ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_END }; 409 | func_args[159] = new ArgTypes[] { ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_END }; 410 | func_args[200] = new ArgTypes[] { ArgTypes.ARG_END }; 411 | func_args[201] = new ArgTypes[] { ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_I2, ArgTypes.ARG_END }; 412 | func_args[202] = new ArgTypes[] { ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_END }; 413 | func_args[203] = new ArgTypes[] { ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_END }; 414 | func_args[204] = new ArgTypes[] { ArgTypes.ARG_END }; 415 | func_args[205] = new ArgTypes[] { ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_R4, ArgTypes.ARG_VT_UI1, ArgTypes.ARG_END }; 416 | func_args[206] = new ArgTypes[] { ArgTypes.ARG_VT_UI1, ArgTypes.ARG_END }; 417 | func_args[207] = new ArgTypes[] { ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_R4, ArgTypes.ARG_END }; 418 | func_args[208] = new ArgTypes[] { ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_I2, ArgTypes.ARG_END }; 419 | func_args[209] = new ArgTypes[] { ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_I2, ArgTypes.ARG_END }; 420 | func_args[210] = new ArgTypes[] { ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_END }; 421 | func_args[211] = new ArgTypes[] { ArgTypes.ARG_STR1, ArgTypes.ARG_PERIOD, ArgTypes.ARG_END }; 422 | func_args[212] = new ArgTypes[] { ArgTypes.ARG_STR3, ArgTypes.ARG_PERIOD, ArgTypes.ARG_VT_I2, ArgTypes.ARG_VT_I2, ArgTypes.ARG_END }; 423 | func_args[230] = new ArgTypes[] { ArgTypes.ARG_VT_UI4, ArgTypes.ARG_VT_UI4, ArgTypes.ARG_END }; 424 | func_args[231] = new ArgTypes[] { ArgTypes.ARG_END }; 425 | func_args[232] = new ArgTypes[] { ArgTypes.ARG_END }; 426 | func_args[240] = new ArgTypes[] { ArgTypes.ARG_VT_UI1, ArgTypes.ARG_END }; 427 | } 428 | 429 | public static bool SetArgTypes(ArgTypes[][] input) 430 | { 431 | if(input.Length != 256) 432 | { 433 | Console.Error.WriteLine("SetArgTypes:传入的参数类型数组大小不正确。"); 434 | return false; 435 | } 436 | func_args = input; 437 | return true; 438 | } 439 | 440 | public static void SaveArgTypes(string path) 441 | { 442 | using (StreamWriter sw = new StreamWriter(path)) 443 | { 444 | for(int i = 0; i < 256; i++) 445 | { 446 | if (func_args[i].Length != 0) 447 | { 448 | StringBuilder sb = new StringBuilder(); 449 | foreach(var t in func_args[i]) 450 | { 451 | sb.Append(t.ToString() + ", "); 452 | } 453 | sw.WriteLine($"{i:X2} {sb.ToString()[..(sb.Length - 2)]}"); 454 | } 455 | else 456 | { 457 | sw.WriteLine($"{i:X2} Empty"); 458 | } 459 | } 460 | sw.Flush(); 461 | sw.Close(); 462 | } 463 | } 464 | 465 | static readonly Dictionary> func_name = new Dictionary>() 466 | { 467 | { 0x01, new("//JX( byte flag, short unk1, float unk2, uint dest1, uint dest2 );", "JX") }, 468 | { 0x02, new("//JMP( uint dest );","JMP") }, 469 | { 0x04, new("//CallFunc( string script_name );","CallFunc") }, 470 | { 0x05, new("","Return") }, 471 | { 0x06, new("//JMP( uint dest );","JMP") }, 472 | { 0x07, new("//JumpTarget( string target_script_name );","JumpTarget") }, 473 | { 0x0F, new("//Selection( byte count );","Selection") }, 474 | { 0x14, new("//Message( uint index, string type? string text );","Message") }, 475 | { 0x15, new("//SetName( string name );","SetName") }, 476 | { 0x33, new("//SetLayer( string layerName, string graphName );","SetLayer") } 477 | }; 478 | 479 | public class Argstruc 480 | { 481 | public string? closure; 482 | public string? arrdef; 483 | } 484 | 485 | static string GetFunctionName(int op, int addr) 486 | { 487 | if (func_name.ContainsKey(op)) 488 | return $"{func_name[op].Item1}\n{addr:d08}: {func_name[op].Item2}"; 489 | else 490 | return $"{addr:d08}: Function_{op:X2}"; 491 | } 492 | 493 | public static Argstruc ParseArgs(byte command, ref int arrc, List args) 494 | { 495 | StringBuilder sb = new StringBuilder(); 496 | Argstruc struc = new Argstruc(); 497 | sb.Append("( "); 498 | var limit = command == 0x0F ? 1 : args.Count; 499 | var i = 0; 500 | for (; i < limit; i++) 501 | { 502 | var arg = args[i]; 503 | if (arg.GetArgType() == ArgTypes.ARG_PERIOD) 504 | { 505 | continue; 506 | } 507 | else if (arg.GetArgType() != ArgTypes.ARG_ARRAY) 508 | { 509 | if (arg.GetArgType() == ArgTypes.ARG_STR1 || arg.GetArgType() == ArgTypes.ARG_STR2 || arg.GetArgType() == ArgTypes.ARG_STR3) 510 | { 511 | sb.Append(string.Format("\"{0}\", ", arg.data)); 512 | } 513 | else 514 | { 515 | sb.Append(string.Format("{0}, ", arg.data)); 516 | } 517 | } 518 | else 519 | { 520 | StringBuilder sb2 = new StringBuilder(); 521 | 522 | if (arg.data is IList list) 523 | { 524 | string typ = arg.data switch 525 | { 526 | List => "byte", 527 | List => "short", 528 | List => "unsigned short", 529 | List => "int", 530 | List => "unsigned int", 531 | List => "float", 532 | List => "string", 533 | _ => throw new Exception("type of arg.data is not valid"), 534 | }; 535 | sb2.Append(string.Format("{0} a{1}[{2}] = {{ ", typ, arrc, list.Count)); 536 | 537 | if (typ == "string") 538 | { 539 | foreach (var elm in list) 540 | { 541 | sb2.Append(string.Format("{0}, ", elm)); 542 | } 543 | } 544 | else 545 | { 546 | foreach (var elm in list) 547 | { 548 | sb2.Append(string.Format("\"{0}\", ", elm)); 549 | } 550 | } 551 | } 552 | 553 | sb.Append(string.Format("a{0}, ", arrc)); 554 | arrc++; 555 | if (struc.arrdef != null) 556 | { 557 | struc.arrdef += sb2.ToString().TrimEnd(new char[] { ' ', ',' }) + " };\n"; 558 | } 559 | else 560 | { 561 | struc.arrdef = sb2.ToString().TrimEnd(new char[] { ' ', ',' }) + " };\n"; 562 | } 563 | } 564 | } 565 | if (i < args.Count - 1)//This means there are some extra params, and that is (at least now) the selection command. 566 | { 567 | struc.closure = sb.ToString().TrimEnd(new char[] { ' ', ',' }) + " );\n"; 568 | var c = 0; 569 | while (i < args.Count) 570 | { 571 | if (args[i + 4].data is Command callback_cmd) 572 | { 573 | struc.closure += string.Format("\tSelection[{0}].set( {1}, \"{2}\", {3}, {4}, \"{5}\" );\n", c, args[i].data, args[i + 1].data, args[i + 2].data, args[i + 3].data, callback_cmd.args[0].data); 574 | c++; 575 | i += 5; 576 | } 577 | else 578 | { 579 | throw new Exception("Selection command is not valid"); 580 | } 581 | } 582 | return struc; 583 | } 584 | struc.closure = sb.ToString().TrimEnd(new char[] { ' ', ',' }) + " );\n"; 585 | return struc; 586 | } 587 | 588 | public static List ReadArgs(byte command, byte[] script, ref int veip) 589 | { 590 | var args = func_args[command]; 591 | List ret = new List(); 592 | for (var argi = 0; argi < args.Length; ++argi) 593 | { 594 | var arg = args[argi]; 595 | if (arg == ArgTypes.ARG_END) 596 | { 597 | break; 598 | } 599 | switch (arg) 600 | { 601 | case ArgTypes.ARG_VT_UI1: 602 | ret.Add(new Arg(arg, script[veip++])); 603 | break; 604 | case ArgTypes.ARG_PERIOD: //for null-terminated str's '\0' 605 | veip++; 606 | break; 607 | case ArgTypes.ARG_VT_I2: 608 | ret.Add(new Arg(arg, BitConverter.ToInt16(script, veip))); 609 | veip += 2; 610 | break; 611 | case ArgTypes.ARG_VT_UI2: 612 | ret.Add(new Arg(arg, BitConverter.ToUInt16(script, veip))); 613 | veip += 2; 614 | break; 615 | case ArgTypes.ARG_VT_INT: 616 | ret.Add(new Arg(arg, BitConverter.ToInt32(script, veip))); 617 | veip += 4; 618 | break; 619 | case ArgTypes.ARG_VT_UI4: 620 | ret.Add(new Arg(arg, BitConverter.ToUInt32(script, veip))); 621 | veip += 4; 622 | break; 623 | case ArgTypes.ARG_VT_R4: 624 | ret.Add(new Arg(arg, BitConverter.ToSingle(script, veip))); 625 | veip += 4; 626 | break; 627 | case ArgTypes.ARG_STR1: 628 | case ArgTypes.ARG_STR2: 629 | case ArgTypes.ARG_STR3: 630 | { 631 | var length = strlen(script, veip); 632 | var bin_arg = new byte[length - 1]; 633 | Array.Copy(script, veip, bin_arg, 0, bin_arg.Length); 634 | ret.Add(new Arg(arg, read_encoding.GetString(bin_arg))); 635 | veip += bin_arg.Length; 636 | break; 637 | } 638 | case ArgTypes.ARG_ARRAY: 639 | { 640 | var array_length = script[veip++]; 641 | argi++; 642 | var elem_type = args[argi]; 643 | switch (elem_type) 644 | { 645 | case ArgTypes.ARG_VT_UI1: 646 | { 647 | List array_val = new List(); 648 | for (var i = 0; i < array_length; i++) 649 | { 650 | array_val.Add(script[veip++]); 651 | } 652 | ret.Add(new Arg(arg, array_length, array_val)); 653 | break; 654 | } 655 | case ArgTypes.ARG_VT_I2: 656 | { 657 | List array_val = new List(); 658 | for (var i = 0; i < array_length; i++) 659 | { 660 | array_val.Add(BitConverter.ToInt16(script, veip)); 661 | veip += 2; 662 | } 663 | ret.Add(new Arg(arg, array_length, array_val)); 664 | break; 665 | } 666 | case ArgTypes.ARG_VT_UI2: 667 | { 668 | List array_val = new List(); 669 | for (var i = 0; i < array_length; i++) 670 | { 671 | array_val.Add(BitConverter.ToUInt16(script, veip)); 672 | veip += 2; 673 | } 674 | ret.Add(new Arg(arg, array_length, array_val)); 675 | break; 676 | } 677 | case ArgTypes.ARG_VT_R4: 678 | { 679 | List array_val = new List(); 680 | for (var i = 0; i < array_length; i++) 681 | { 682 | array_val.Add(BitConverter.ToSingle(script, veip)); 683 | veip += 4; 684 | } 685 | ret.Add(new Arg(arg, array_length, array_val)); 686 | break; 687 | } 688 | case ArgTypes.ARG_VT_UI4: 689 | { 690 | List array_val = new List(); 691 | for (var i = 0; i < array_length; i++) 692 | { 693 | array_val.Add(BitConverter.ToUInt32(script, veip)); 694 | veip += 4; 695 | } 696 | ret.Add(new Arg(arg, array_length, array_val)); 697 | break; 698 | } 699 | case ArgTypes.ARG_VT_INT: 700 | { 701 | List array_val = new List(); 702 | for (var i = 0; i < array_length; i++) 703 | { 704 | array_val.Add(BitConverter.ToInt32(script, veip)); 705 | veip += 4; 706 | } 707 | ret.Add(new Arg(arg, array_length, array_val)); 708 | break; 709 | } 710 | case ArgTypes.ARG_STR1: 711 | case ArgTypes.ARG_STR2: 712 | case ArgTypes.ARG_STR3: 713 | { 714 | List array_val = new List(); 715 | for (var i = 0; i < array_length; i++) 716 | { 717 | var length = strlen(script, veip); 718 | var bin_arg = new byte[length - 1]; 719 | Array.Copy(script, veip, bin_arg, 0, bin_arg.Length); 720 | array_val.Add(read_encoding.GetString(bin_arg)); 721 | veip += bin_arg.Length + 1; 722 | } 723 | ret.Add(new Arg(arg, array_length, array_val)); 724 | break; 725 | } 726 | default: 727 | throw new Exception(string.Format("Invalid Array Type:{0}", elem_type)); 728 | } 729 | break; 730 | } 731 | default: 732 | break; 733 | } 734 | } 735 | if (command == 0x0F)//This is a choice command 736 | { 737 | if (ret[0].data is byte num) 738 | { 739 | for (var i = 0; i < num; i++) 740 | { 741 | ret.Add(new Arg(ArgTypes.ARG_VT_UI2, BitConverter.ToUInt16(script, veip))); 742 | veip += 2; 743 | var length = strlen(script, veip); 744 | var bin_arg = new byte[length - 1]; 745 | Array.Copy(script, veip, bin_arg, 0, bin_arg.Length); 746 | ret.Add(new Arg(ArgTypes.ARG_STR1, read_encoding.GetString(bin_arg))); 747 | veip += bin_arg.Length + 1; 748 | ret.Add(new Arg(ArgTypes.ARG_VT_UI1, script[veip++])); 749 | ret.Add(new Arg(ArgTypes.ARG_VT_I2, BitConverter.ToInt16(script, veip))); 750 | veip += 2; 751 | var ncommand = script[veip++]; 752 | ret.Add(new Arg(ArgTypes.ARG_CALLBACK, new Command(ref veip, ncommand, script))); 753 | } 754 | } 755 | else 756 | { 757 | throw new Exception("Selection count invalid"); 758 | } 759 | } 760 | return ret; 761 | } 762 | 763 | public static byte[] WriteArgs(List args) 764 | { 765 | var ret = new List(); 766 | foreach (var o in args) 767 | { 768 | switch (o.GetArgType()) 769 | { 770 | case ArgTypes.ARG_VT_UI1: 771 | if (o.data is byte b) ret.Add(b); 772 | break; 773 | case ArgTypes.ARG_VT_I2: 774 | if (o.data is short s) ret.AddRange(BitConverter.GetBytes(s)); 775 | break; 776 | case ArgTypes.ARG_VT_UI2: 777 | if (o.data is ushort us) ret.AddRange(BitConverter.GetBytes(us)); 778 | break; 779 | case ArgTypes.ARG_VT_INT: 780 | if (o.data is int i) ret.AddRange(BitConverter.GetBytes(i)); 781 | break; 782 | case ArgTypes.ARG_VT_UI4: 783 | if (o.data is uint ui) ret.AddRange(BitConverter.GetBytes(ui)); 784 | break; 785 | case ArgTypes.ARG_VT_R4: 786 | if (o.data is float f) ret.AddRange(BitConverter.GetBytes(f)); 787 | break; 788 | case ArgTypes.ARG_STR1: 789 | case ArgTypes.ARG_STR2: 790 | case ArgTypes.ARG_STR3: 791 | if (o.data is string str) ret.AddRange(write_encoding.GetBytes(str)); 792 | ret.Add(0); 793 | break; 794 | case ArgTypes.ARG_ARRAY: 795 | { 796 | if (o.data is IList list) 797 | { 798 | //1byte数组长度,要保证长度不会超过byte所能表示的大小 799 | ret.Add((byte)list.Count); 800 | foreach (var elm in list) 801 | { 802 | switch (elm) 803 | { 804 | case byte elmb: 805 | ret.Add(elmb); 806 | break; 807 | case short elms: 808 | ret.AddRange(BitConverter.GetBytes(elms)); 809 | break; 810 | case ushort elmus: 811 | ret.AddRange(BitConverter.GetBytes(elmus)); 812 | break; 813 | case int elmi: 814 | ret.AddRange(BitConverter.GetBytes(elmi)); 815 | break; 816 | case uint elmui: 817 | ret.AddRange(BitConverter.GetBytes(elmui)); 818 | break; 819 | case float elmf: 820 | ret.AddRange(BitConverter.GetBytes(elmf)); 821 | break; 822 | case string elmstr: 823 | ret.AddRange(write_encoding.GetBytes(elmstr)); 824 | ret.Add(0); 825 | break; 826 | default: 827 | throw new Exception("Unexpected array type."); 828 | } 829 | } 830 | } 831 | break; 832 | } 833 | case ArgTypes.ARG_CALLBACK: 834 | if (o.data is Command cmd) 835 | { 836 | ret.AddRange(cmd.GetBytes()); 837 | } 838 | break; 839 | default: 840 | break; 841 | } 842 | } 843 | return ret.ToArray(); 844 | } 845 | 846 | static int strlen(byte[] input, int offset) 847 | { 848 | var i = 0; 849 | while (input[offset + i++] != '\0') ; 850 | return i; 851 | } 852 | } 853 | } 854 | -------------------------------------------------------------------------------- /Program.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | using System.Runtime.Serialization.Json; 3 | using Newtonsoft.Json; 4 | using System.Diagnostics; 5 | using System.Collections; 6 | using ws2Parse.PE; 7 | 8 | namespace ws2Parse 9 | { 10 | internal class Program 11 | { 12 | static void Main(string[] args) 13 | { 14 | Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); 15 | //CLegacyFunctions.UpdateVM1993(); 16 | //CLegacyFunctions.SaveArgTypes(@"E:\GalGames_Work\OnWork\个人研究向\懱尡斉杮懱\1993.txt"); 17 | 18 | if (args.Length < 3) 19 | { 20 | Console.WriteLine("使用方法:ws2Parse.exe [AdvHD主程序路径] [存放ws2文件的文件夹路径] [功能(d:解包|r:封包)]"); 21 | return; 22 | } 23 | 24 | CLegacyFunctions.SetArgTypes(ArgAnalyzer.ExtractArgTypes(args[0])); 25 | //CLegacyFunctions.SaveArgTypes(@"E:\GalGames_Work\OnWork\个人研究向\懱尡斉杮懱\1996.txt"); 26 | switch(args[2]) 27 | { 28 | case "d": 29 | ExportAllStrings(args[1]); 30 | break; 31 | case "p": 32 | ReassembleAllScripts(args[1]); 33 | break; 34 | case "dc": 35 | DecompileScripts(args[1]); 36 | break; 37 | default: 38 | Console.WriteLine("未知模式,请检查您的输入!"); 39 | break; 40 | } 41 | 42 | //ReAssemWithUtf8(args[0]); 43 | //ReassembleAllScripts(args[0]); 44 | //DecryptScripts(args[0]); 45 | //ws.Decompile(args[0]); 46 | //ws.ImportStrings(args[0]); 47 | //ws.Assem(args[0]); 48 | //WS2Script.Encrypt(ref script); 49 | //File.WriteAllBytes(BaseBame + ".ws2", script); 50 | } 51 | 52 | static void ReAssemWithUtf8(string folder) 53 | { 54 | WS2Script ws = new(); 55 | ws.Load(@"start.ws2"); 56 | //ws.LoadJson(@"start.json"); 57 | ws.Assemble(@"start.ws2", true); 58 | 59 | 60 | 61 | foreach (string file in Directory.EnumerateFiles(folder, "*.ws2", SearchOption.TopDirectoryOnly)) 62 | { 63 | ws.Load(file); 64 | ws.Assemble(file, true); 65 | } 66 | } 67 | 68 | 69 | static void ExportAllStrings(string folder, bool decrypt = false) 70 | { 71 | WS2Script ws = new(); 72 | foreach (string file in Directory.EnumerateFiles(folder, "*.ws2", SearchOption.TopDirectoryOnly)) 73 | { 74 | ws.Load(file, decrypt); 75 | ws.ExportStrings(file); 76 | } 77 | using (StreamWriter sw = new StreamWriter(Path.Combine(folder, "人名表.txt"))) 78 | { 79 | sw.WriteLine(JsonConvert.SerializeObject(ws.char_names, Formatting.Indented)); 80 | sw.Flush(); 81 | sw.Close(); 82 | } 83 | Console.WriteLine(string.Format("总字数统计:约{0}字", ws.total_chars)); 84 | } 85 | 86 | static void ReassembleAllScripts(string folder, bool importstrings = true, bool decrypt = false, bool encrypt = false) 87 | { 88 | WS2Script ws = new(); 89 | try 90 | { 91 | if(JsonConvert.DeserializeObject>(File.ReadAllText(Path.Combine(folder, "人名表.txt"))) is Dictionary dic) 92 | { 93 | ws.char_names = dic; 94 | } 95 | else 96 | { 97 | throw new Exception("人名表反序列化错误。"); 98 | } 99 | 100 | }catch (Exception ex) 101 | { 102 | Console.Error.WriteLine(ex.Message); 103 | Console.Error.WriteLine("读取人名表的时候出错啦!检查一下吧"); 104 | return; 105 | } 106 | 107 | foreach (string file in Directory.EnumerateFiles(folder, "*.ws2", SearchOption.TopDirectoryOnly)) 108 | { 109 | Console.WriteLine($"Processing: {file}"); 110 | ws.Load(file, decrypt); 111 | string txt_file = Path.ChangeExtension(file, "txt"); 112 | if(File.Exists(txt_file) && importstrings) 113 | { 114 | ws.ImportStrings(txt_file); 115 | } 116 | ws.Assemble(file, encrypt); 117 | } 118 | } 119 | 120 | static void DecompileScripts(string input, bool decrypt = false) 121 | { 122 | WS2Script ws = new(); 123 | if (Directory.Exists(input)) 124 | { 125 | foreach (string file in Directory.EnumerateFiles(input, "*.ws2", SearchOption.TopDirectoryOnly)) 126 | { 127 | Console.WriteLine($"Processing: {file}"); 128 | ws.Load(file, decrypt); 129 | ws.Decompile(file); 130 | } 131 | } 132 | else 133 | { 134 | Console.WriteLine($"Processing: {input}"); 135 | ws.Load(input, decrypt); 136 | ws.Decompile(input); 137 | } 138 | } 139 | 140 | static void DecryptScripts(string input) 141 | { 142 | WS2Script ws = new(); 143 | if (Directory.Exists(input)) 144 | { 145 | foreach (string file in Directory.EnumerateFiles(input, "*.ws2", SearchOption.TopDirectoryOnly)) 146 | { 147 | ws.DecryptScript(file); 148 | } 149 | } 150 | else 151 | { 152 | ws.DecryptScript(input); 153 | } 154 | } 155 | 156 | } 157 | 158 | } -------------------------------------------------------------------------------- /Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "ws2Parse": { 4 | "commandName": "Project", 5 | "commandLineArgs": "\"E:\\GalGames_Work\\OnWork\\个人研究向\\懱尡斉杮懱\\AdvHD.exe\" \"E:\\GalGames_Work\\OnWork\\个人研究向\\懱尡斉杮懱\\RIO\" \"dc\"" 6 | } 7 | } 8 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # .ws2脚本工具 4 | 5 | #### 注意:这个工具现在还没有写完!现在只支持1.9.9.10及某些更旧的版本(虽然已经可以用来处理文本了) 6 | 7 | 目前它支持以下功能: 8 | 9 | - 加密/解密 `.ws2` 文件 10 | - 导出所有对话相关指令的字符串参数(用于翻译) 11 | - 将上面导出的字符串使用另一种编码导入回去(比如gbk或者utf-8,不过utf8编码支持需要稍微魔改一下游戏主程序才行) 12 | - 把 `.ws2` 文件拆成 `.json` 和`.txt`文件(类似于反编译,可以查看脚本里面到底是怎么样的命令) 13 | - 自动从exe里提取出vm的参数列表数组用于提取文本/反编译(目前还只支持少数几个版本,因为每个版本的特征码都不一样,很烦) 14 | 15 | 使用方法(命令行): 16 | 17 | ``` 18 | ws2Parse.exe [AdvHD的主程序的路径(不支持加壳的版本)] [存放ws2文件的文件夹路径] [功能(d:解包|r:封包)] 19 | ``` 20 | 21 | 使用例: 22 | 23 | ``` 24 | ws2Parse.exe "E:\Game\AdvHD.exe" "E:\Game\Rio" "d" 25 | ``` 26 | 27 | --- 28 | 29 | ## 以下是对ws2进行的一点说明(进阶内容) 30 | 31 | `ws2`是`AdvHD`引擎所使用的一种文件格式,内部存储的是`AdvHD`内置的`vm`能够解析并执行的字节码。 32 | 33 | 对于`AdvHD`来说,一条ws2指令有两个主要组成部分: 34 | 35 | + 指令:一字节大小,不同指令对应不同的功能,多种功能组合在一起组成了游戏内各种各样的演出效果 36 | + 参数:不定长,参数个数以及参数类型由指令所决定 37 | 38 | 在`AdvHD`中,指令的取值范围是0~255。但并不是每一个值都有其对应的指令。即便在最新版中,在0xA2以后也有很多空指令存在。体现在代码中,则如下面片段所示: 39 | 40 | ```c 41 | void FillCLegacyFunctions(legacygame *this) 42 | { 43 | result = memset(&this->CLegacyFuncs, 0, sizeof(this->CLegacyFuncs));//256*4 44 | this->CLegacyFuncs.handler[0] = sub_44FFC0; // always return TRUE 45 | this->CLegacyFuncs.handler[1] = VM_ConditionalJump; 46 | this->CLegacyFuncs.handler[2] = VM_Jump; 47 | this->CLegacyFuncs.handler[4] = VM_CallFunction; // call1(string script) 48 | this->CLegacyFuncs.handler[5] = VM_FunctionReturn; // return 49 | this->CLegacyFuncs.handler[6] = VM_Jump; // jump (inside of the script) 50 | this->CLegacyFuncs.handler[7] = VM_CallScript; // noreturn_call(string script) 51 | this->CLegacyFuncs.handler[8] = sub_4505B0; // post_message 52 | this->CLegacyFuncs.handler[9] = sub_450600; // var_calc 53 | this->CLegacyFuncs.handler[0xA] = sub_4509F0; // mod 54 | this->CLegacyFuncs.handler[0xF] = VM_Select; 55 | this->CLegacyFuncs.handler[0x11] = VM_Timer; 56 | this->CLegacyFuncs.handler[0x12] = VM_TimerState; 57 | this->CLegacyFuncs.handler[0x14] = VM_Mes; 58 | this->CLegacyFuncs.handler[0x15] = VM_MesName; 59 | this->CLegacyFuncs.handler[0x16] = VM_MesWinState; // SetState(bool state) -> open/close 60 | this->CLegacyFuncs.handler[0x1A] = VM_CallLua; 61 | this->CLegacyFuncs.handler[0x1B] = VM_OpenConfig; 62 | this->CLegacyFuncs.handler[0x1D] = VM_ChangeMesWin; 63 | //... 64 | this->CLegacyFuncs.handler[0xFE] = sub_462050; 65 | this->CLegacyFuncs.handler[0xFF] = sub_462200; 66 | } 67 | ``` 68 | 69 | 如果要执行这些空指令,则会触发`空指针异常`。 70 | 71 | `ws2`指令在被执行之前,必须要得到他的参数。一条`ws2`指令可以消耗一个或多个参数,无论这个指令使用了多少参数,`AdvHD`都会将他们存入`std::vector`中。由于每个参数都会使用`VARIANTARG`保存,即该`vector`的类型为`std::vector`。 72 | 73 | 那么`AdvHD`是怎么知道某个指令到底有哪些参数、每个参数又是什么样的类型的呢?原来,`AdvHD`主程序内部硬编码了一个数组,这个数组存储着每个指令所对应的参数类型数组的指针。`AdvHD`会在这个数组中用下标获得每个指令所需的参数列表,并根据这个列表逐个从脚本中取得参数,而`vm`的`vmeip`随之后移。 74 | 75 | 若当前指令所需的所有参数均正确读入,则读取完成后,`vmeip`正好指向下一条`ws2`指令的头部。 76 | 77 | `ws2`共有如下参数类型: 78 | 79 | | 参数名 | 枚举值 | 等价类型 | 参数大小(字节) | 备注 | 80 | | ------------ | ------ | -------------- | ---------------- | ------------------------------------------------------------ | 81 | | ARG_VT_UI1 | 0x00 | unsigned char | 1 | | 82 | | ARG_VT_I2 | 0x01 | short | 2 | | 83 | | ARG_VT_UI2 | 0x02 | unsigned short | 2 | | 84 | | ARG_VT_INT | 0x03 | int | 4 | | 85 | | ARG_VT_UI4 | 0x04 | unsigned int | 4 | | 86 | | ARG_VT_R4 | 0x05 | float | 4 | | 87 | | ARG_STR1 | 0x06 | char* | 不定长 | | 88 | | ARG_ARRAY | 0x07 | | 1 | 不单独出现,参数为数组长度,其在参数列表中的后一个参数类型代表该数组的元素类型 | 89 | | ARG_PERIOD | 0x08 | '\0' | 1 | 不单独出现,必定在`ARG_STR1`或`ARG_STR2`或`ARG_STR3`后面(也就是字符串结束符啦) | 90 | | ARG_STR2 | 0x09 | char* | 不定长 | | 91 | | ARG_STR3 | 0x0A | char* | 不定长 | | 92 | | ARG_CALLBACK | 0xFE | | 不定长 | 参数内容是一条ws2指令,通常用于选项跳转 | 93 | | ARG_END | 0xFF | | 0 | 代表参数列表结尾,遇到该值时停止获取参数 | 94 | 95 | 参数列表数组对应到代码中如下所示: 96 | 97 | ```c 98 | byte a[] = { 0xFF };//没有参数的指令 99 | byte b[] = { 0x0, 0xFF };//一个参数,参数类型是byte的指令 100 | byte c[] = { 0x07, 0x3, 0xFF };//参数类型是一个int数组 101 | byte d[] = { 0x00, 0x06, 0x08, 0xFF };//参数类型是一个byte和一个字符串 102 | //... 103 | 104 | static byte* arg_types[256]; 105 | 106 | arg_types[0] = a; 107 | arg_types[1] = b; 108 | arg_types[2] = c; 109 | arg_types[3] = d; 110 | //... 111 | ``` 112 | 113 | 因为我们的最终目标是翻译游戏,因此我们将目光聚焦在这三个字符串类型上。通过对`AdvHD`的代码的分析我们可以知道,游戏内显示的文本其类型为`ARG_STR1`。我们找到处理该参数读入的代码处查看具体实现: 114 | 115 | ![image-20230613194524700](https://github.com/pkuislm/ws2Parse/blob/master/note_imgs/image-20230613194524700.png) 116 | 117 | 我们能看到三种类型的字符串都在使用同一个逻辑。点开`sub_4A8030`看看: 118 | 119 | ![image-20230613194548453](https://github.com/pkuislm/ws2Parse/blob/master/note_imgs/image-20230613194548453.png) 120 | 121 | 可以看到是这里的函数将`ANSI`编码的字符串转换成了`Unicode`字符串,也就是说`AdvHD`内部的编码是`Unicode`的。(新版本的`AdvHD`在这里的编码转换会写成0x3A4也就是CP932,但是除此之外,代码逻辑在各个版本中并没有太大变化。) 122 | 123 | 若要调整文本编码,主要有下面两种方式: 124 | 125 | + 直接暴力该值,把这里的值改成0x3A8(GBK)或者0xFDE9(UTF-8)。 126 | + 复制一份sub_4A8030,并对其副本进行改动,最后将字符串处理里面的编码转换函数改成这个副本 127 | 128 | 我个人不推荐第一种方案,因为不能保证这个编码转换函数只被这里调用。为保证其余功能的正常运行,我们不能随意更改原始函数。这里我推荐第二种方法。第二种方法实行起来有很多种方式,可以写hook,也可以直接复制粘贴汇编。我在这里就不多做赘述。 129 | 130 | ps:还有一种更好的方案,就是仅对`case 6`做改动。我们知道`switch`用的是跳转表,我们仅需在其跳转表的位置做出改动即可调整这个`case`的行为。这样做虽然会稍微麻烦一些,但比起第二种方案要更加稳妥(因为没人知道`ARG_STR2`和`ARG_STR3`会不会传入多字节字符) 131 | 132 | --- 133 | 134 | 135 | 136 | # A tool for AdvHD's `.ws2` script 137 | 138 | #### NOTE: This tool is not completed yet! It only supports AdvHD v1.9.9.10 and some older versions. 139 | 140 | Currently, it implements the following features: 141 | 142 | - Decrypt/Encrypt `.ws2` files 143 | - Export strings related to message command(for translation) 144 | - Import strings with a different encoding(gbk, utf-8) 145 | - Disassemble `.ws2` file into `.json` file 146 | - Automatically extract vm functions' arguments layout from exe(only support a few versions) 147 | 148 | *** 149 | 150 | Notice that different versions of AdvHD are not the same in terms of instructions, for example, the newer version will likely add some instructions or modify some existing instructions, so it's necessary to figure out the difference between them. 151 | 152 | #### Some details about the `.ws2 ` 153 | 154 | The script basically consists of a list of opcodes and arguments like this: 155 | 156 | ``` 157 | [opcode][args][opcode][args]...[end of script][extra params] 158 | ``` 159 | 160 | *The `end of script` is byte 0xFF, and `extra params` is two `Int32` (Currently I don't know what these two numbers mean at the moment, maybe they have something to do with the VM's stack size?) 161 | 162 | When the engine reads a certain opcode, it will find the number of parameters it has and their types according to the opcode, and then read these parameters in sequence. 163 | 164 | AdvHD has its own enum to distinguish different types of arguments, and it uses `VARIANTARG` to store them. 165 | 166 | For more details, you can see the source code. 167 | 168 | -------------------------------------------------------------------------------- /WS2Script.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections; 4 | using System.Collections.Generic; 5 | using System.Diagnostics; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace ws2Parse 11 | { 12 | public class WS2Script 13 | { 14 | List commands; 15 | byte[] param; 16 | public int total_chars { get; private set; } 17 | public Dictionary char_names { get; set; } = new Dictionary(); 18 | int single_chars; 19 | 20 | public WS2Script() 21 | { 22 | commands = new List(); 23 | param = new byte[8]; 24 | total_chars = 0; 25 | single_chars = 0; 26 | } 27 | 28 | void Encrypt(ref byte[] script) 29 | { 30 | for (var i = 0; i < script.Length; ++i) 31 | { 32 | script[i] = (byte)((byte)(script[i] >> 6) | (byte)(script[i] << 2)); 33 | } 34 | } 35 | void Decrypt(ref byte[] script) 36 | { 37 | for (var i = 0; i < script.Length; ++i) 38 | { 39 | script[i] = (byte)((byte)(script[i] >> 2) | (byte)(script[i] << 6)); 40 | } 41 | } 42 | 43 | public void DecryptScript(string BaseName) 44 | { 45 | var bytes = File.ReadAllBytes(BaseName); 46 | Decrypt(ref bytes); 47 | File.WriteAllBytes(Path.ChangeExtension(BaseName, ".ws2.dec"), bytes); 48 | } 49 | public void EncryptScript(string BaseName) 50 | { 51 | var bytes = File.ReadAllBytes(BaseName); 52 | Encrypt(ref bytes); 53 | File.WriteAllBytes(Path.ChangeExtension(BaseName, ".ws2.enc"), bytes); 54 | } 55 | 56 | public void Load(string BaseName, bool decrypt = false) 57 | { 58 | if (commands.Count != 0) commands.Clear(); 59 | var script = File.ReadAllBytes(BaseName); 60 | if (decrypt) Decrypt(ref script); 61 | var veip = 0; 62 | while (veip < script.Length) 63 | { 64 | //var offset = veip; 65 | var command = script[veip++]; 66 | if (command == 0xFF) 67 | { 68 | //脚本末端 69 | commands.Add(new CLegacyFunctions.Command(ref veip, command)); 70 | Debug.Assert((script.Length - veip) == 8); 71 | Array.Copy(script, veip, param, 0, 8);//不知道这个是什么,暂时按原样复制过去 72 | break; 73 | } 74 | commands.Add(new CLegacyFunctions.Command(ref veip, command, script)); 75 | } 76 | } 77 | public void LoadJson(string BaseName, bool decrypt = false) 78 | { 79 | if (commands.Count != 0) commands.Clear(); 80 | 81 | var obj = JsonConvert.DeserializeObject(File.ReadAllText(BaseName)); 82 | if (obj is IList list) 83 | { 84 | foreach (var i in list) 85 | { 86 | commands.Add((CLegacyFunctions.Command)i); 87 | } 88 | } 89 | } 90 | 91 | public void Decompile(string BaseName) 92 | { 93 | int arrc = 0; 94 | using (StreamWriter sw = new StreamWriter(Path.ChangeExtension(BaseName, ".dis.txt"))) 95 | { 96 | foreach (CLegacyFunctions.Command cmd in commands) 97 | { 98 | var tmp = CLegacyFunctions.ParseArgs(cmd.op, ref arrc, cmd.args); 99 | sw.Write($"{tmp.arrdef}{cmd.name}{tmp.closure}"); 100 | } 101 | 102 | sw.Flush(); 103 | sw.Close(); 104 | } 105 | using (StreamWriter sw = new StreamWriter(Path.ChangeExtension(BaseName, "json"))) 106 | { 107 | sw.WriteLine(JsonConvert.SerializeObject(commands, Formatting.Indented)); 108 | sw.Flush(); 109 | sw.Close(); 110 | } 111 | } 112 | 113 | //Notice that in the future version of AdvHD, you probably need to add more vm opcodes here to ensure offset capabilities 114 | //Format: {opcode, [positions of the arg that represent a offset]} 115 | readonly Dictionary> offsetFixList = new Dictionary>() 116 | { 117 | //Conditional jump 118 | { 0x01, new List{ 3, 4 } }, 119 | //jump 120 | { 0x02, new List{ 0 } }, 121 | { 0x06, new List{ 0 } }, 122 | //For 19910 123 | { 0xE6, new List{ 0, 1 } }, 124 | }; 125 | 126 | public void Assemble(string BaseName, bool encrypt = false) 127 | { 128 | using (MemoryStream ms = new()) 129 | { 130 | //old/new 131 | Dictionary offset_dic = new Dictionary(); 132 | //index/start_offset 133 | Dictionary offset_offsets = new Dictionary(); 134 | for (var i = 0; i < commands.Count; ++i) 135 | { 136 | //i.offset.cur = (int)ms.Position; 137 | offset_dic.Add(commands[i].offset.old, (uint)ms.Position); 138 | if (offsetFixList.ContainsKey(commands[i].op)) 139 | { 140 | offset_offsets.Add(i, (int)ms.Position); 141 | } 142 | ms.Write(commands[i].GetBytes()); 143 | } 144 | //ms.WriteByte(0xFF); 145 | ms.Write(param); 146 | 147 | //fix jumps 148 | foreach (var i in offset_offsets.Keys) 149 | { 150 | ms.Seek(offset_offsets[i], SeekOrigin.Begin); 151 | 152 | if(offsetFixList.TryGetValue(commands[i].op, out List? idxes)) 153 | { 154 | foreach(var idx in idxes) 155 | { 156 | if(commands[i].args[idx].data is uint val) commands[i].args[idx].data = offset_dic[val]; 157 | } 158 | } 159 | 160 | ms.Write(commands[i].GetBytes()); 161 | } 162 | 163 | byte[] bytes = ms.ToArray(); 164 | if (encrypt) Encrypt(ref bytes); 165 | File.WriteAllBytes(Path.ChangeExtension(BaseName, ".ws2.new"), bytes); 166 | } 167 | } 168 | 169 | public void ExportStrings(string output) 170 | { 171 | single_chars = 0; 172 | using (StreamWriter sw = new StreamWriter(Path.ChangeExtension(output, "txt"))) 173 | { 174 | for (var i = 0; i < commands.Count; ++i) 175 | { 176 | if (commands[i].op == 0x14) 177 | { 178 | if (commands[i].args[2].data is string s) 179 | { 180 | single_chars += s.Length; 181 | if (s == "%P") 182 | { 183 | continue; 184 | } 185 | 186 | if (i == 0) 187 | { 188 | sw.WriteLine(string.Format("☆{0:X8}☆☆{1}\n★{0:X8}★★{1}\n", commands[i].args[0].data, s)); 189 | } 190 | else 191 | { 192 | if (commands[i - 1].op != 0x15) 193 | { 194 | bool b = false; 195 | //他在有message的时候,除了前面是个选项,其他情况下理论上都会调用一次SetName。所以向前搜索一下看看 196 | for (var t = 1; t <= 2; t++) 197 | { 198 | if (commands[i - 1 - t].op == 0x15) 199 | { 200 | sw.WriteLine(string.Format("☆{0:X8}☆{1}☆{2}\n★{0:X8}★{1}★{2}\n", commands[i].args[0].data, commands[i - 1 - t].args[0].data, s)); 201 | if (commands[i - 1 - t].args[0].data is string ch_name) 202 | { 203 | if (!char_names.TryGetValue(ch_name, out string? a)) 204 | { 205 | char_names.Add(ch_name, ch_name); 206 | } 207 | } 208 | 209 | b = true; 210 | break; 211 | } 212 | } 213 | //如果真找不到那确实就有点离谱了,可能是没见过的模式,需要Decompile这个脚本然后找到那个位置看看 214 | if (!b) throw new Exception("No name was set before message command."); 215 | } 216 | else 217 | { 218 | sw.WriteLine(string.Format("☆{0:X8}☆{1}☆{2}\n★{0:X8}★{1}★{2}\n", commands[i].args[0].data, commands[i - 1].args[0].data, s)); 219 | if (commands[i - 1].args[0].data is string ch_name) 220 | { 221 | if (!char_names.TryGetValue(ch_name, out string? a)) 222 | { 223 | char_names.Add(ch_name, ch_name); 224 | } 225 | } 226 | } 227 | } 228 | } 229 | } 230 | else if (commands[i].op == 0x0F) 231 | { 232 | if (commands[i].args[0].data is byte count) 233 | { 234 | for (var j = 0; j < count; ++j) 235 | { 236 | if (commands[i].args[j * 5 + 2].data is string s) 237 | { 238 | sw.WriteLine("☆{0:X8}☆选项{1}☆{2}\n★{0:X8}★选项{1}★{2}\n", commands[i].args[j * 5 + 1].data, j + 1, s); 239 | single_chars += s.Length; 240 | } 241 | } 242 | } 243 | } 244 | } 245 | } 246 | total_chars += single_chars; 247 | Console.WriteLine(string.Format("{0} :约{1}字", output[(output.LastIndexOf('\\') + 1)..], single_chars)); 248 | } 249 | 250 | public void ImportStrings(string input) 251 | { 252 | List text_strings = new List(); 253 | using (StreamReader sr = new StreamReader(input)) 254 | { 255 | string? line; 256 | while (!sr.EndOfStream) 257 | { 258 | line = sr.ReadLine(); 259 | if (line != null && line.StartsWith('★')) 260 | { 261 | text_strings.Add(line[10..]); 262 | } 263 | } 264 | } 265 | var text_index = 0; 266 | for (var i = 0; i < commands.Count; ++i) 267 | { 268 | if (commands[i].op == 0x14) 269 | { 270 | if (commands[i].args[2].data is string s) 271 | { 272 | if (s == "%P") 273 | { 274 | continue; 275 | } 276 | } 277 | if (i == 0) 278 | { 279 | commands[i].args[2].data = text_strings[text_index][(text_strings[text_index].IndexOf('★') + 1)..]; 280 | text_index++; 281 | } 282 | else 283 | { 284 | if (commands[i - 1].op != 0x15) 285 | { 286 | bool b = false; 287 | for (var t = 1; t <= 2; t++) 288 | { 289 | if (commands[i - 1 - t].op == 0x15) 290 | { 291 | if (char_names.TryGetValue(text_strings[text_index][..text_strings[text_index].IndexOf('★')], out string? name_cn)) 292 | { 293 | commands[i - 1 - t].args[0].data = name_cn; 294 | } 295 | else 296 | { 297 | commands[i - 1 - t].args[0].data = text_strings[text_index][..text_strings[text_index].IndexOf('★')]; 298 | } 299 | 300 | commands[i].args[2].data = text_strings[text_index][(text_strings[text_index].IndexOf('★') + 1)..]; 301 | text_index++; 302 | b = true; 303 | break; 304 | } 305 | } 306 | if (!b) throw new Exception("No name was set before message command."); 307 | } 308 | else 309 | { 310 | if (char_names.TryGetValue(text_strings[text_index][..text_strings[text_index].IndexOf('★')], out string? name_cn)) 311 | { 312 | commands[i - 1].args[0].data = name_cn; 313 | } 314 | else 315 | { 316 | commands[i - 1].args[0].data = text_strings[text_index][..text_strings[text_index].IndexOf('★')]; 317 | } 318 | commands[i].args[2].data = text_strings[text_index][(text_strings[text_index].IndexOf('★') + 1)..]; 319 | text_index++; 320 | } 321 | } 322 | 323 | } 324 | else if (commands[i].op == 0x0F) 325 | { 326 | if (commands[i].args[0].data is byte count) 327 | { 328 | for (var j = 0; j < count; ++j) 329 | { 330 | commands[i].args[j * 5 + 2].data = text_strings[text_index][(text_strings[text_index].IndexOf('★') + 1)..]; 331 | text_index++; 332 | } 333 | } 334 | } 335 | } 336 | } 337 | } 338 | } 339 | -------------------------------------------------------------------------------- /backup.txt: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | using System.Runtime.Serialization.Json; 3 | using Newtonsoft.Json; 4 | 5 | namespace ws2Parse 6 | { 7 | internal class Program 8 | { 9 | static void Main(string[] args) 10 | { 11 | Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); 12 | //var encoding = Encoding.GetEncoding("unicode"); 13 | var BaseBame = @"E:\GalGames_Work\OnWork\ココロ@ファンクション!\RIO\cocoro_com_001"; 14 | var script = File.ReadAllBytes(BaseBame + ".ws2.old"); 15 | 16 | List script_commands = new List(); 17 | 18 | var veip = 0; 19 | while( veip < script.Length ) 20 | { 21 | //var offset = veip; 22 | var command = script[veip++]; 23 | if (command == 0xFF) 24 | { 25 | Console.WriteLine("Code ends."); 26 | break; 27 | } 28 | //var arg_list = CLegacyFunctions.GetArgs(command, script, ref veip); 29 | script_commands.Add(new CLegacyFunctions.Command(ref veip, command, script)); 30 | } 31 | using (StreamWriter sw = new StreamWriter(BaseBame + ".json")) 32 | { 33 | sw.WriteLine(JsonConvert.SerializeObject(script_commands, Formatting.Indented)); 34 | sw.Flush(); 35 | sw.Close(); 36 | } 37 | using (StreamWriter sw = new StreamWriter(BaseBame + ".txt")) 38 | { 39 | sw.WriteLine(CLegacyFunctions.Decompile(script_commands)); 40 | sw.Flush(); 41 | sw.Close(); 42 | } 43 | for(var i = 0; i < script.Length; ++i) 44 | { 45 | script[i] = (byte)((byte)(script[i] >> 6) | (byte)(script[i] << 2)); 46 | } 47 | File.WriteAllBytes(BaseBame + ".ws2", script); 48 | } 49 | 50 | 51 | 52 | } 53 | public static class CLegacyFunctions 54 | { 55 | public class Arg 56 | { 57 | public string type; 58 | AT etype; 59 | public object data; 60 | 61 | public Arg(AT type, object data) 62 | { 63 | etype = type; 64 | this.type = type.ToString(); 65 | this.data = data; 66 | } 67 | 68 | public Arg(AT type, int count, object data) 69 | { 70 | etype = type; 71 | this.type = string.Format("{0}[{1}]", type.ToString(), count); ; 72 | this.data = data; 73 | } 74 | 75 | public AT GetArgType() 76 | { 77 | return etype; 78 | } 79 | } 80 | 81 | public class Command 82 | { 83 | public int offset; 84 | public int op; 85 | public string name; 86 | public List args; 87 | 88 | public Command(ref int veip, byte op, byte[] script) 89 | { 90 | offset = veip; 91 | this.op = op; 92 | args = GetArgs(op, script, ref veip); 93 | name = GetFunctionName(op); 94 | } 95 | } 96 | 97 | public enum AT 98 | { 99 | U0 = 0, 100 | U1 = 1, 101 | U2 = 2, 102 | U3 = 3, 103 | U4 = 4, 104 | U5 = 5, 105 | U6 = 6, 106 | U7 = 7, 107 | U8 = 8, 108 | U9 = 9, 109 | UA = 0x0A, 110 | ARG_END = 0xFF 111 | } 112 | 113 | static readonly AT[][] func_args = new AT[256][] 114 | { 115 | new AT[]{ 0xFF }, 116 | new AT[]{ 0, 1, 5, 4, 4, 0xFF },//JX 117 | new AT[]{ 4, 0xFF },//JMP 118 | Array.Empty(), 119 | new AT[]{ 0x0A, 8, 0xFF }, 120 | new AT[]{ 0xFF }, 121 | new AT[]{ 4, 0xFF },//JMP 122 | new AT[]{ 0x0A, 8, 0xFF }, 123 | new AT[]{ 0, 0xFF }, 124 | new AT[]{ 0, 1, 5, 0xFF }, 125 | new AT[]{ 1, 5, 0xFF }, 126 | new AT[]{ 1, 0, 0xFF }, 127 | new AT[]{ 1, 0, 7, 1, 0xFF }, 128 | new AT[]{ 1, 1, 5, 0xFF }, 129 | new AT[]{ 1, 1, 0, 0xFF }, 130 | new AT[]{ 0, 0xFF }, 131 | Array.Empty(), 132 | new AT[]{ 6, 8, 5, 0xFF },//17-6805 FF 133 | new AT[]{ 6, 8, 0, 0x0A, 8, 0xFF }, 134 | new AT[]{ 0xFF }, 135 | new AT[]{ 4, 6, 8, 6, 8, 0xFF },//20-468680 FF 136 | new AT[]{ 6, 8, 0xFF },//21-680 FF 137 | new AT[]{ 0, 0xFF },//22-00 FF 138 | new AT[]{ 0xFF }, 139 | new AT[]{ 0, 6, 8, 0xFF }, 140 | new AT[]{ 0xFF }, 141 | new AT[]{ 6, 8, 0xFF }, 142 | new AT[]{ 0, 0xFF }, 143 | new AT[]{ 6, 8, 6, 8, 1, 0, 0xFF }, 144 | new AT[]{ 1, 0xFF }, 145 | new AT[]{ 6, 8, 0x0A, 8, 5, 5, 1, 1, 0, 0xFF },//30-68A8551105 FF 146 | new AT[]{ 6, 8, 5, 0xFF }, 147 | new AT[]{ 6, 8, 5, 1, 0xFF }, 148 | new AT[]{ 6, 8, 1, 1, 1, 0xFF }, 149 | new AT[]{ 6, 8, 0, 0xFF }, 150 | Array.Empty(), 151 | Array.Empty(), 152 | Array.Empty(), 153 | Array.Empty(), 154 | Array.Empty(), 155 | new AT[]{ 6, 8, 0x0A, 8, 5, 5, 1, 1, 0, 1, 1, 0, 0xFF },//40-68A8551101105 FF 156 | new AT[]{ 6, 8, 5, 0xFF }, 157 | new AT[]{ 6, 8, 5, 1, 0xFF }, 158 | new AT[]{ 6, 8, 0xFF }, 159 | new AT[]{ 6, 8, 0xFF }, 160 | new AT[]{ 6, 8, 0, 0xFF }, 161 | new AT[]{ 0xFF }, 162 | new AT[]{ 6, 8, 1, 5, 0xFF }, 163 | Array.Empty(), 164 | Array.Empty(), 165 | new AT[]{ 0x0A, 8, 0xFF }, 166 | new AT[]{ 6, 8, 0x0A, 8, 0, 0, 0xFF }, 167 | new AT[]{ 6, 8, 0x0A, 8, 0, 0, 0xFF }, 168 | new AT[]{ 6, 8, 0x0A, 8, 0, 0, 0, 0xFF }, 169 | new AT[]{ 6, 8, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0xFF }, 170 | new AT[]{ 6, 8, 0xFF }, 171 | new AT[]{ 6, 8, 0, 0xFF }, 172 | new AT[]{ 6, 8, 0, 0, 7, 1, 0xFF }, 173 | new AT[]{ 6, 8, 0, 0, 0xFF }, 174 | new AT[]{ 6, 8, 6, 8, 1, 1, 1, 5, 5, 5, 5, 5, 5, 5, 5, 0xFF }, 175 | new AT[]{ 6, 8, 0xFF }, 176 | new AT[]{ 1, 0xFF }, 177 | new AT[]{ 0xFF }, 178 | new AT[]{ 7, 6, 0xFF },//string arr 179 | new AT[]{ 6, 8, 0x0A, 8, 0, 0xFF }, 180 | new AT[]{ 6, 8, 0, 0xFF }, 181 | new AT[]{ 6, 8, 1, 0xFF }, 182 | new AT[]{ 6, 8, 0xFF }, 183 | new AT[]{ 6, 8, 6, 8, 0, 0xFF }, 184 | new AT[]{ 6, 8, 1, 5, 5, 5, 5, 0xFF }, 185 | new AT[]{ 6, 8, 1, 0, 5, 5, 5, 5, 0xFF }, 186 | new AT[]{ 6, 8, 6, 8, 1, 0, 0, 5, 5, 5, 5, 5, 1, 5, 0xFF }, 187 | new AT[]{ 6, 8, 6, 8, 1, 0, 0, 0x0A, 8, 0xFF }, 188 | new AT[]{ 6, 8, 6, 8, 0x0A, 8, 0xFF }, 189 | new AT[]{ 6, 8, 6, 8, 0xFF }, 190 | new AT[]{ 6, 8, 1, 1, 5, 5, 5, 5, 0xFF }, 191 | new AT[]{ 6, 8, 1, 1, 0, 5, 5, 5, 5, 0xFF }, 192 | new AT[]{ 6, 8, 6, 8, 1, 1, 0, 0, 5, 5, 5, 5, 5, 1, 5, 0xFF }, 193 | new AT[]{ 6, 8, 6, 8, 1, 1, 0, 0, 0x0A, 8, 0xFF }, 194 | new AT[]{ 6, 8, 6, 8, 1, 0x0A, 8, 0xFF }, 195 | new AT[]{ 6, 8, 6, 8, 1, 0xFF }, 196 | new AT[]{ 6, 8, 6, 8, 1, 5, 0, 0xFF }, 197 | new AT[]{ 6, 8, 6, 8, 5, 1, 5, 0, 0x0A, 8, 0xFF }, 198 | new AT[]{ 6, 8, 6, 8, 0xFF }, 199 | new AT[]{ 6, 8, 6, 8, 0x0A, 8, 0xFF }, 200 | new AT[]{ 6, 8, 6, 8, 0xFF }, 201 | new AT[]{ 6, 8, 0, 1, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, 0, 1, 6, 8, 1, 6, 8, 0x0A, 8, 5, 0xFF }, 202 | new AT[]{ 6, 8, 1, 0xFF }, 203 | new AT[]{ 6, 8, 6, 8, 0xFF }, 204 | new AT[]{ 6, 8, 6, 8, 1, 0xFF }, 205 | new AT[]{ 6, 8, 7, 1, 0xFF }, 206 | new AT[]{ 6, 8, 1, 0, 0xFF }, 207 | new AT[]{ 6, 8, 0xFF }, 208 | new AT[]{ 6, 8, 6, 8, 0,0xFF }, 209 | new AT[]{ 6, 8, 5, 5, 0xFF }, 210 | Array.Empty(),//95-A8 FF 211 | Array.Empty(),//96-1111 FF 212 | Array.Empty(),//97-05555 FF 213 | Array.Empty(),//98-68 FF 214 | Array.Empty(),//99-680 FF 215 | new AT[]{ 0, 0xFF }, 216 | new AT[]{ 1, 0, 5, 5, 0, 0x0A, 8, 0xFF }, 217 | new AT[]{ 0x0A, 8, 0xFF }, 218 | new AT[]{ 0, 0, 1, 5, 5, 5, 5, 5, 0, 0xFF }, 219 | new AT[]{ 0, 0xFF }, 220 | Array.Empty(),//105-68005555515 FF 221 | Array.Empty(),//106-68100A8 FF 222 | Array.Empty(),//107-6868 FF 223 | Array.Empty(),//108-6855 FF 224 | Array.Empty(), 225 | new AT[]{ 9, 8, 9, 8, 0xFF },//110-9868 FF 226 | new AT[]{ 9, 8, 0xFF }, 227 | new AT[]{ 9, 8, 1, 0xFF }, 228 | new AT[]{ 0xFF }, 229 | new AT[]{ 9, 8, 1, 1, 9, 8, 0xFF }, 230 | new AT[]{ 9, 8, 9, 8, 1, 0xFF }, 231 | new AT[]{ 9, 8, 9, 8, 0xFF }, 232 | new AT[]{ 9, 8, 6, 8, 0xFF }, 233 | Array.Empty(), 234 | Array.Empty(), 235 | new AT[]{ 6, 8, 0x0A, 8, 0, 0, 0xFF },//120-68A8000 FF 236 | new AT[]{ 6, 8, 6, 8, 5, 0xFF }, 237 | new AT[]{ 6, 8, 0x0A, 8, 5, 0, 0, 0x0A, 8, 0xFF }, 238 | new AT[]{ 6, 8, 0x0A, 8, 0xFF }, 239 | new AT[]{ 6, 8, 6, 8, 5, 0xFF }, 240 | new AT[]{ 6, 8, 5, 0xFF }, 241 | new AT[]{ 6, 8, 0xFF }, 242 | #region unused 243 | Array.Empty(),//127-6855555 FF 244 | Array.Empty(),//128-68 FF 245 | Array.Empty(),//129-680A8550 FF 246 | Array.Empty(),//130-68A85 FF 247 | Array.Empty(),//131-686855 FF 248 | Array.Empty(),//132-686868515 FF 249 | Array.Empty(),//133-686805 FF 250 | Array.Empty(),//134-68555 FF 251 | Array.Empty(),//135-685 FF 252 | Array.Empty(),//136-686868515 FF 253 | Array.Empty(), 254 | Array.Empty(), 255 | Array.Empty(), 256 | Array.Empty(),//140-68A86800 FF 257 | Array.Empty(),//141-4686800A8 FF 258 | Array.Empty(),//142-4686800A8 FF 259 | Array.Empty(),//143-68A8 FF 260 | Array.Empty(),//144-68 FF 261 | Array.Empty(), 262 | Array.Empty(), 263 | Array.Empty(), 264 | Array.Empty(), 265 | Array.Empty(), 266 | Array.Empty(),//150-15555 FF 267 | Array.Empty(),//151-105555 FF 268 | Array.Empty(),//152-681005555515 FF 269 | Array.Empty(),//153-68100A8 FF 270 | Array.Empty(),//154-FF 271 | Array.Empty(),//155-68 FF 272 | Array.Empty(),//156-68A8 FF 273 | Array.Empty(),//157-68 FF 274 | Array.Empty(),//158-680 FF 275 | Array.Empty(),//159-680 FF 276 | Array.Empty(), 277 | Array.Empty(), 278 | Array.Empty(), 279 | Array.Empty(), 280 | Array.Empty(), 281 | Array.Empty(), 282 | Array.Empty(), 283 | Array.Empty(), 284 | Array.Empty(), 285 | Array.Empty(), 286 | Array.Empty(), 287 | Array.Empty(), 288 | Array.Empty(), 289 | Array.Empty(), 290 | Array.Empty(), 291 | Array.Empty(), 292 | Array.Empty(), 293 | Array.Empty(), 294 | Array.Empty(), 295 | Array.Empty(), 296 | Array.Empty(), 297 | Array.Empty(), 298 | Array.Empty(), 299 | Array.Empty(), 300 | Array.Empty(), 301 | Array.Empty(), 302 | Array.Empty(), 303 | Array.Empty(), 304 | Array.Empty(), 305 | Array.Empty(), 306 | Array.Empty(), 307 | Array.Empty(), 308 | Array.Empty(), 309 | Array.Empty(), 310 | Array.Empty(), 311 | Array.Empty(), 312 | Array.Empty(), 313 | Array.Empty(), 314 | Array.Empty(), 315 | Array.Empty(), 316 | Array.Empty(),//200-FF 317 | Array.Empty(),//201-68681111 FF 318 | Array.Empty(),//202-6868 FF 319 | Array.Empty(),//203-6800 FF 320 | Array.Empty(),//204-FF 321 | Array.Empty(),//205-686868686850 FF 322 | Array.Empty(),//206-0 FF 323 | Array.Empty(),//207-68685 FF 324 | Array.Empty(),//208-681 FF 325 | Array.Empty(),//209-681 FF 326 | Array.Empty(),//210-68 FF 327 | Array.Empty(),//211-68 FF 328 | Array.Empty(),//212-A811 FF 329 | Array.Empty(), 330 | Array.Empty(), 331 | Array.Empty(), 332 | Array.Empty(), 333 | Array.Empty(), 334 | Array.Empty(), 335 | Array.Empty(), 336 | Array.Empty(), 337 | Array.Empty(), 338 | Array.Empty(), 339 | Array.Empty(), 340 | Array.Empty(), 341 | Array.Empty(), 342 | Array.Empty(), 343 | Array.Empty(), 344 | Array.Empty(), 345 | Array.Empty(), 346 | Array.Empty(),//230-44 FF 347 | Array.Empty(),//231-FF 348 | Array.Empty(),//232-FF 349 | Array.Empty(), 350 | Array.Empty(), 351 | Array.Empty(), 352 | Array.Empty(), 353 | Array.Empty(), 354 | Array.Empty(), 355 | Array.Empty(), 356 | Array.Empty(),//240-0 FF 357 | Array.Empty(), 358 | Array.Empty(), 359 | Array.Empty(), 360 | Array.Empty(), 361 | Array.Empty(), 362 | Array.Empty(), 363 | Array.Empty(), 364 | #endregion unused 365 | new AT[] { 0xFF }, 366 | new AT[] { 0, 0x0A, 8, 0xFF }, 367 | new AT[] { 0xFF }, 368 | new AT[] { 0, 0xFF }, 369 | new AT[] { 1, 0xFF }, 370 | new AT[] { 0xFF }, 371 | new AT[] { 6, 8, 0xFF }, 372 | Array.Empty()//ScriptEnd 373 | }; 374 | 375 | static readonly Dictionary func_name = new Dictionary() 376 | { 377 | { 0x01, "//JX( byte flag, short unk1, float unk2, uint dest1, uint dest2 );\nJX" }, 378 | { 0x02, "//JMP( uint dest );\nJMP" }, 379 | { 0x04, "//CallFunc( string script_name );\nCallFunc" }, 380 | { 0x05, "Return" }, 381 | { 0x06, "//JMP( uint dest );\nJMP" }, 382 | { 0x07, "//CallScript( string script_name );\nCallScript" }, 383 | { 0x14, "//Message( uint index, string type? string text );\nMessage" }, 384 | { 0x15, "//SetName( string name );\nSetName" } 385 | }; 386 | 387 | class Argstruc 388 | { 389 | public string? closure; 390 | public string? arrdef; 391 | } 392 | 393 | static string GetFunctionName(int op) 394 | { 395 | if (func_name.ContainsKey(op)) 396 | return func_name[op]; 397 | else 398 | return $"F_{op:X2}"; 399 | } 400 | 401 | public static string Decompile(List commands) 402 | { 403 | StringBuilder sb = new StringBuilder(); 404 | foreach (Command cmd in commands) 405 | { 406 | var tmp = ParseArgs(cmd.args); 407 | sb.Append(tmp.arrdef); 408 | sb.Append(cmd.name); 409 | sb.Append(tmp.closure); 410 | sb.Append('\n'); 411 | } 412 | return sb.ToString(); 413 | } 414 | 415 | static Argstruc ParseArgs(List args) 416 | { 417 | StringBuilder sb = new StringBuilder(); 418 | Argstruc struc = new Argstruc(); 419 | sb.Append("( "); 420 | int arrc = 0; 421 | foreach (var arg in args) 422 | { 423 | if(arg.GetArgType() != 7) 424 | { 425 | if(arg.GetArgType() == 6 || arg.GetArgType() == 9 || arg.GetArgType() == 0x0A) 426 | { 427 | sb.Append(string.Format("\"{0}\", ", arg.data)); 428 | } 429 | else 430 | { 431 | sb.Append(string.Format("{0}, ", arg.data)); 432 | } 433 | } 434 | else 435 | { 436 | StringBuilder sb2 = new StringBuilder(); 437 | 438 | if(arg.data.GetType() == typeof(List)) 439 | { 440 | if (arg.data is List tdata) 441 | { 442 | sb2.Append(string.Format("byte a{0}[{1}] = {{ ", arrc, tdata.Count)); 443 | foreach (var t in tdata) 444 | { 445 | sb2.Append(string.Format("{0}, ", t)); 446 | } 447 | } 448 | } 449 | else if(arg.data.GetType() == typeof(List)) 450 | { 451 | if (arg.data is List tdata) 452 | { 453 | sb2.Append(string.Format("short a{0}[{1}] = {{ ", arrc, tdata.Count)); 454 | foreach (var t in tdata) 455 | { 456 | sb2.Append(string.Format("{0}, ", t)); 457 | } 458 | } 459 | } 460 | else if(arg.data.GetType() == typeof(List)) 461 | { 462 | if (arg.data is List tdata) 463 | { 464 | sb2.Append(string.Format("unsigned short a{0}[{1}] = {{ ", arrc, tdata.Count)); 465 | foreach (var t in tdata) 466 | { 467 | sb2.Append(string.Format("{0}, ", t)); 468 | } 469 | } 470 | } 471 | else if(arg.data.GetType() == typeof(List)) 472 | { 473 | if (arg.data is List tdata) 474 | { 475 | sb2.Append(string.Format("float a{0}[{1}] = {{ ", arrc, tdata.Count)); 476 | foreach (var t in tdata) 477 | { 478 | sb2.Append(string.Format("{0}, ", t)); 479 | } 480 | } 481 | } 482 | else if(arg.data.GetType() == typeof(List)) 483 | { 484 | if (arg.data is List tdata) 485 | { 486 | sb2.Append(string.Format("int a{0}[{1}] = {{ ", arrc, tdata.Count)); 487 | foreach (var t in tdata) 488 | { 489 | sb2.Append(string.Format("{0}, ", t)); 490 | } 491 | } 492 | } 493 | else if(arg.data.GetType() == typeof(List)) 494 | { 495 | if (arg.data is List tdata) 496 | { 497 | sb2.Append(string.Format("unsigned int a{0}[{1}] = {{ ", arrc, tdata.Count)); 498 | foreach(var t in tdata) 499 | { 500 | sb2.Append(string.Format("{0}, ", t)); 501 | } 502 | } 503 | } 504 | else if(arg.data.GetType() == typeof(List)) 505 | { 506 | if (arg.data is List tdata) 507 | { 508 | sb2.Append(string.Format("string a{0}[{1}] = {{ ", arrc, tdata.Count)); 509 | foreach (var s in tdata) 510 | { 511 | sb2.Append(string.Format("\"{0}\", ", s)); 512 | } 513 | } 514 | } 515 | else 516 | { 517 | throw new Exception("type of arg.data is not valid"); 518 | } 519 | sb.Append(string.Format("a{0}, ", arrc)); 520 | arrc++; 521 | if (struc.arrdef != null) 522 | { 523 | struc.arrdef += sb2.ToString().TrimEnd(new char[] { ' ', ',' }) + " };\n"; 524 | } 525 | else 526 | { 527 | struc.arrdef = sb2.ToString().TrimEnd(new char[] { ' ', ',' }) + " };\n"; 528 | } 529 | } 530 | } 531 | struc.closure = sb.ToString().TrimEnd(new char[] { ' ', ',' }) + " );\n"; 532 | return struc; 533 | } 534 | 535 | static List GetArgs(byte command, byte[] script, ref int veip) 536 | { 537 | var args = func_args[command]; 538 | var encoding = Encoding.GetEncoding("shift_jis"); 539 | List ret = new List(); 540 | for(var argi = 0; argi < args.Length; ++argi) 541 | { 542 | var arg = args[argi]; 543 | if (arg == 0xFF) 544 | { 545 | break; 546 | } 547 | switch (arg) 548 | { 549 | case 0: 550 | ret.Add(new Arg(arg, script[veip++])); 551 | break; 552 | case 8: //for null-terminated str's '\0' ? 553 | veip++; 554 | break; 555 | case 1: 556 | ret.Add(new Arg(arg, BitConverter.ToInt16(script, veip))); 557 | veip += 2; 558 | break; 559 | case AT.U2: 560 | ret.Add(new Arg(arg, BitConverter.ToUInt16(script, veip))); 561 | veip += 2; 562 | break; 563 | case AT.U3: 564 | ret.Add(new Arg(arg, BitConverter.ToInt32(script, veip))); 565 | veip += 4; 566 | break; 567 | case 4: 568 | ret.Add(new Arg(arg, BitConverter.ToUInt32(script, veip))); 569 | veip += 4; 570 | break; 571 | case 5: 572 | ret.Add(new Arg(arg, BitConverter.ToSingle(script, veip))); 573 | veip += 4; 574 | break; 575 | case 6: 576 | case 9: 577 | case 0x0A: 578 | { 579 | var length = strlen(script, veip); 580 | var bin_arg = new byte[length - 1]; 581 | Array.Copy(script, veip, bin_arg, 0, bin_arg.Length); 582 | ret.Add(new Arg(arg, encoding.GetString(bin_arg))); 583 | veip += bin_arg.Length; 584 | break; 585 | } 586 | case 7: 587 | { 588 | var array_length = script[veip++]; 589 | argi++; 590 | var elem_type = args[argi]; 591 | switch(elem_type) 592 | { 593 | case 0: 594 | { 595 | List array_val = new List(); 596 | for (var i = 0; i < array_length; i++) 597 | { 598 | array_val.Add(script[veip++]); 599 | } 600 | ret.Add(new Arg(arg, array_length, array_val)); 601 | break; 602 | } 603 | case 1: 604 | { 605 | List array_val = new List(); 606 | for (var i = 0; i < array_length; i++) 607 | { 608 | array_val.Add(BitConverter.ToInt16(script, veip)); 609 | veip += 2; 610 | } 611 | ret.Add(new Arg(arg, array_length, array_val)); 612 | break; 613 | } 614 | case AT.U2: 615 | { 616 | List array_val = new List(); 617 | for (var i = 0; i < array_length; i++) 618 | { 619 | array_val.Add(BitConverter.ToUInt16(script, veip)); 620 | veip += 2; 621 | } 622 | ret.Add(new Arg(arg, array_length, array_val)); 623 | break; 624 | } 625 | case 5: 626 | { 627 | List array_val = new List(); 628 | for (var i = 0; i < array_length; i++) 629 | { 630 | array_val.Add(BitConverter.ToSingle(script, veip)); 631 | veip += 4; 632 | } 633 | ret.Add(new Arg(arg, array_length, array_val)); 634 | break; 635 | } 636 | case 4: 637 | { 638 | List array_val = new List(); 639 | for (var i = 0; i < array_length; i++) 640 | { 641 | array_val.Add(BitConverter.ToUInt32(script, veip)); 642 | veip += 4; 643 | } 644 | ret.Add(new Arg(arg, array_length, array_val)); 645 | break; 646 | } 647 | case AT.U3: 648 | { 649 | List array_val = new List(); 650 | for (var i = 0; i < array_length; i++) 651 | { 652 | array_val.Add(BitConverter.ToInt32(script, veip)); 653 | veip += 4; 654 | } 655 | ret.Add(new Arg(arg, array_length, array_val)); 656 | break; 657 | } 658 | case 6: 659 | case 9: 660 | case 0x0A: 661 | { 662 | List array_val = new List(); 663 | for (var i = 0; i < array_length; i++) 664 | { 665 | var length = strlen(script, veip); 666 | var bin_arg = new byte[length - 1]; 667 | Array.Copy(script, veip, bin_arg, 0, bin_arg.Length); 668 | array_val.Add(encoding.GetString(bin_arg)); 669 | veip += bin_arg.Length + 1; 670 | } 671 | ret.Add(new Arg(arg, array_length, array_val)); 672 | break; 673 | } 674 | default: 675 | throw new Exception(string.Format("Invalid Array Type:{0}", elem_type)); 676 | } 677 | break; 678 | } 679 | default: 680 | break; 681 | } 682 | } 683 | return ret; 684 | } 685 | static int strlen(byte[] input, int offset) 686 | { 687 | var i = 0; 688 | while (input[offset + i++] != '\0') ; 689 | return i; 690 | } 691 | } 692 | } -------------------------------------------------------------------------------- /note_imgs/image-20230613194524700.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pkuislm/ws2Parse/c6740d00374c55db3c50b11abb5765c51c6684df/note_imgs/image-20230613194524700.png -------------------------------------------------------------------------------- /note_imgs/image-20230613194548453.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pkuislm/ws2Parse/c6740d00374c55db3c50b11abb5765c51c6684df/note_imgs/image-20230613194548453.png -------------------------------------------------------------------------------- /ws2Parse.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /ws2Parse.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.2.32630.192 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ws2Parse", "ws2Parse.csproj", "{E8FAD9A8-FF76-4C60-9181-D7FEEAEDD56D}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {E8FAD9A8-FF76-4C60-9181-D7FEEAEDD56D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {E8FAD9A8-FF76-4C60-9181-D7FEEAEDD56D}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {E8FAD9A8-FF76-4C60-9181-D7FEEAEDD56D}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {E8FAD9A8-FF76-4C60-9181-D7FEEAEDD56D}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {C1B86192-4B85-4309-982A-EE35B946B2EA} 24 | EndGlobalSection 25 | EndGlobal 26 | --------------------------------------------------------------------------------