mirror of
https://github.com/Perfare/Il2CppDumper.git
synced 2025-01-25 02:03:02 -03:00
NSO支持
This commit is contained in:
parent
182580c90c
commit
5d26d0f480
7 changed files with 880 additions and 11 deletions
|
@ -47,6 +47,9 @@
|
|||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Lz4DecoderStream.cs" />
|
||||
<Compile Include="NSO.cs" />
|
||||
<Compile Include="NSOClass.cs" />
|
||||
<Compile Include="VersionAttribute.cs" />
|
||||
<Compile Include="Config.cs" />
|
||||
<Compile Include="DummyAssemblyCreator.cs" />
|
||||
|
|
540
Il2CppDumper/Lz4DecoderStream.cs
Normal file
540
Il2CppDumper/Lz4DecoderStream.cs
Normal file
|
@ -0,0 +1,540 @@
|
|||
#define CHECK_ARGS
|
||||
#define CHECK_EOF
|
||||
//#define LOCAL_SHADOW
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Lz4
|
||||
{
|
||||
public class Lz4DecoderStream : Stream
|
||||
{
|
||||
public Lz4DecoderStream(Stream input, long inputLength = long.MaxValue)
|
||||
{
|
||||
Reset(input, inputLength);
|
||||
}
|
||||
|
||||
private void Reset(Stream input, long inputLength = long.MaxValue)
|
||||
{
|
||||
this.inputLength = inputLength;
|
||||
this.input = input;
|
||||
|
||||
phase = DecodePhase.ReadToken;
|
||||
|
||||
decodeBufferPos = 0;
|
||||
|
||||
litLen = 0;
|
||||
matLen = 0;
|
||||
matDst = 0;
|
||||
|
||||
inBufPos = DecBufLen;
|
||||
inBufEnd = DecBufLen;
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (disposing && input != null)
|
||||
{
|
||||
input.Close();
|
||||
}
|
||||
input = null;
|
||||
decodeBuffer = null;
|
||||
}
|
||||
finally
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
|
||||
private long inputLength;
|
||||
private Stream input;
|
||||
|
||||
//because we might not be able to match back across invocations,
|
||||
//we have to keep the last window's worth of bytes around for reuse
|
||||
//we use a circular buffer for this - every time we write into this
|
||||
//buffer, we also write the same into our output buffer
|
||||
|
||||
private const int DecBufLen = 0x10000;
|
||||
private const int DecBufMask = 0xFFFF;
|
||||
|
||||
private const int InBufLen = 128;
|
||||
|
||||
private byte[] decodeBuffer = new byte[DecBufLen + InBufLen];
|
||||
private int decodeBufferPos, inBufPos, inBufEnd;
|
||||
|
||||
//we keep track of which phase we're in so that we can jump right back
|
||||
//into the correct part of decoding
|
||||
|
||||
private DecodePhase phase;
|
||||
|
||||
private enum DecodePhase
|
||||
{
|
||||
ReadToken,
|
||||
ReadExLiteralLength,
|
||||
CopyLiteral,
|
||||
ReadOffset,
|
||||
ReadExMatchLength,
|
||||
CopyMatch,
|
||||
}
|
||||
|
||||
//state within interruptable phases and across phase boundaries is
|
||||
//kept here - again, so that we can punt out and restart freely
|
||||
|
||||
private int litLen, matLen, matDst;
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
#if CHECK_ARGS
|
||||
if (buffer == null)
|
||||
throw new ArgumentNullException("buffer");
|
||||
if (offset < 0 || count < 0 || buffer.Length - count < offset)
|
||||
throw new ArgumentOutOfRangeException();
|
||||
|
||||
if (input == null)
|
||||
throw new InvalidOperationException();
|
||||
#endif
|
||||
int nRead, nToRead = count;
|
||||
|
||||
var decBuf = decodeBuffer;
|
||||
|
||||
//the stringy gotos are obnoxious, but their purpose is to
|
||||
//make it *blindingly* obvious how the state machine transitions
|
||||
//back and forth as it reads - remember, we can yield out of
|
||||
//this routine in several places, and we must be able to re-enter
|
||||
//and pick up where we left off!
|
||||
|
||||
#if LOCAL_SHADOW
|
||||
var phase = this.phase;
|
||||
var inBufPos = this.inBufPos;
|
||||
var inBufEnd = this.inBufEnd;
|
||||
#endif
|
||||
switch (phase)
|
||||
{
|
||||
case DecodePhase.ReadToken:
|
||||
goto readToken;
|
||||
|
||||
case DecodePhase.ReadExLiteralLength:
|
||||
goto readExLiteralLength;
|
||||
|
||||
case DecodePhase.CopyLiteral:
|
||||
goto copyLiteral;
|
||||
|
||||
case DecodePhase.ReadOffset:
|
||||
goto readOffset;
|
||||
|
||||
case DecodePhase.ReadExMatchLength:
|
||||
goto readExMatchLength;
|
||||
|
||||
case DecodePhase.CopyMatch:
|
||||
goto copyMatch;
|
||||
}
|
||||
|
||||
readToken:
|
||||
int tok;
|
||||
if (inBufPos < inBufEnd)
|
||||
{
|
||||
tok = decBuf[inBufPos++];
|
||||
}
|
||||
else
|
||||
{
|
||||
#if LOCAL_SHADOW
|
||||
this.inBufPos = inBufPos;
|
||||
#endif
|
||||
|
||||
tok = ReadByteCore();
|
||||
#if LOCAL_SHADOW
|
||||
inBufPos = this.inBufPos;
|
||||
inBufEnd = this.inBufEnd;
|
||||
#endif
|
||||
#if CHECK_EOF
|
||||
if (tok == -1)
|
||||
goto finish;
|
||||
#endif
|
||||
}
|
||||
|
||||
litLen = tok >> 4;
|
||||
matLen = (tok & 0xF) + 4;
|
||||
|
||||
switch (litLen)
|
||||
{
|
||||
case 0:
|
||||
phase = DecodePhase.ReadOffset;
|
||||
goto readOffset;
|
||||
|
||||
case 0xF:
|
||||
phase = DecodePhase.ReadExLiteralLength;
|
||||
goto readExLiteralLength;
|
||||
|
||||
default:
|
||||
phase = DecodePhase.CopyLiteral;
|
||||
goto copyLiteral;
|
||||
}
|
||||
|
||||
readExLiteralLength:
|
||||
int exLitLen;
|
||||
if (inBufPos < inBufEnd)
|
||||
{
|
||||
exLitLen = decBuf[inBufPos++];
|
||||
}
|
||||
else
|
||||
{
|
||||
#if LOCAL_SHADOW
|
||||
this.inBufPos = inBufPos;
|
||||
#endif
|
||||
exLitLen = ReadByteCore();
|
||||
#if LOCAL_SHADOW
|
||||
inBufPos = this.inBufPos;
|
||||
inBufEnd = this.inBufEnd;
|
||||
#endif
|
||||
|
||||
#if CHECK_EOF
|
||||
if (exLitLen == -1)
|
||||
goto finish;
|
||||
#endif
|
||||
}
|
||||
|
||||
litLen += exLitLen;
|
||||
if (exLitLen == 255)
|
||||
goto readExLiteralLength;
|
||||
|
||||
phase = DecodePhase.CopyLiteral;
|
||||
goto copyLiteral;
|
||||
|
||||
copyLiteral:
|
||||
int nReadLit = litLen < nToRead ? litLen : nToRead;
|
||||
if (nReadLit != 0)
|
||||
{
|
||||
if (inBufPos + nReadLit <= inBufEnd)
|
||||
{
|
||||
int ofs = offset;
|
||||
|
||||
for (int c = nReadLit; c-- != 0;)
|
||||
buffer[ofs++] = decBuf[inBufPos++];
|
||||
|
||||
nRead = nReadLit;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if LOCAL_SHADOW
|
||||
this.inBufPos = inBufPos;
|
||||
#endif
|
||||
nRead = ReadCore(buffer, offset, nReadLit);
|
||||
#if LOCAL_SHADOW
|
||||
inBufPos = this.inBufPos;
|
||||
inBufEnd = this.inBufEnd;
|
||||
#endif
|
||||
#if CHECK_EOF
|
||||
if (nRead == 0)
|
||||
goto finish;
|
||||
#endif
|
||||
}
|
||||
|
||||
offset += nRead;
|
||||
nToRead -= nRead;
|
||||
|
||||
litLen -= nRead;
|
||||
|
||||
if (litLen != 0)
|
||||
goto copyLiteral;
|
||||
}
|
||||
|
||||
if (nToRead == 0)
|
||||
goto finish;
|
||||
|
||||
phase = DecodePhase.ReadOffset;
|
||||
goto readOffset;
|
||||
|
||||
readOffset:
|
||||
if (inBufPos + 1 < inBufEnd)
|
||||
{
|
||||
matDst = (decBuf[inBufPos + 1] << 8) | decBuf[inBufPos];
|
||||
inBufPos += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if LOCAL_SHADOW
|
||||
this.inBufPos = inBufPos;
|
||||
#endif
|
||||
matDst = ReadOffsetCore();
|
||||
#if LOCAL_SHADOW
|
||||
inBufPos = this.inBufPos;
|
||||
inBufEnd = this.inBufEnd;
|
||||
#endif
|
||||
#if CHECK_EOF
|
||||
if (matDst == -1)
|
||||
goto finish;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (matLen == 15 + 4)
|
||||
{
|
||||
phase = DecodePhase.ReadExMatchLength;
|
||||
goto readExMatchLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
phase = DecodePhase.CopyMatch;
|
||||
goto copyMatch;
|
||||
}
|
||||
|
||||
readExMatchLength:
|
||||
int exMatLen;
|
||||
if (inBufPos < inBufEnd)
|
||||
{
|
||||
exMatLen = decBuf[inBufPos++];
|
||||
}
|
||||
else
|
||||
{
|
||||
#if LOCAL_SHADOW
|
||||
this.inBufPos = inBufPos;
|
||||
#endif
|
||||
exMatLen = ReadByteCore();
|
||||
#if LOCAL_SHADOW
|
||||
inBufPos = this.inBufPos;
|
||||
inBufEnd = this.inBufEnd;
|
||||
#endif
|
||||
#if CHECK_EOF
|
||||
if (exMatLen == -1)
|
||||
goto finish;
|
||||
#endif
|
||||
}
|
||||
|
||||
matLen += exMatLen;
|
||||
if (exMatLen == 255)
|
||||
goto readExMatchLength;
|
||||
|
||||
phase = DecodePhase.CopyMatch;
|
||||
goto copyMatch;
|
||||
|
||||
copyMatch:
|
||||
int nCpyMat = matLen < nToRead ? matLen : nToRead;
|
||||
if (nCpyMat != 0)
|
||||
{
|
||||
nRead = count - nToRead;
|
||||
|
||||
int bufDst = matDst - nRead;
|
||||
if (bufDst > 0)
|
||||
{
|
||||
//offset is fairly far back, we need to pull from the buffer
|
||||
|
||||
int bufSrc = decodeBufferPos - bufDst;
|
||||
if (bufSrc < 0)
|
||||
bufSrc += DecBufLen;
|
||||
int bufCnt = bufDst < nCpyMat ? bufDst : nCpyMat;
|
||||
|
||||
for (int c = bufCnt; c-- != 0;)
|
||||
buffer[offset++] = decBuf[bufSrc++ & DecBufMask];
|
||||
}
|
||||
else
|
||||
{
|
||||
bufDst = 0;
|
||||
}
|
||||
|
||||
int sOfs = offset - matDst;
|
||||
for (int i = bufDst; i < nCpyMat; i++)
|
||||
buffer[offset++] = buffer[sOfs++];
|
||||
|
||||
nToRead -= nCpyMat;
|
||||
matLen -= nCpyMat;
|
||||
}
|
||||
|
||||
if (nToRead == 0)
|
||||
goto finish;
|
||||
|
||||
phase = DecodePhase.ReadToken;
|
||||
goto readToken;
|
||||
|
||||
finish:
|
||||
nRead = count - nToRead;
|
||||
|
||||
int nToBuf = nRead < DecBufLen ? nRead : DecBufLen;
|
||||
int repPos = offset - nToBuf;
|
||||
|
||||
if (nToBuf == DecBufLen)
|
||||
{
|
||||
Buffer.BlockCopy(buffer, repPos, decBuf, 0, DecBufLen);
|
||||
decodeBufferPos = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
int decPos = decodeBufferPos;
|
||||
|
||||
while (nToBuf-- != 0)
|
||||
decBuf[decPos++ & DecBufMask] = buffer[repPos++];
|
||||
|
||||
decodeBufferPos = decPos & DecBufMask;
|
||||
}
|
||||
|
||||
#if LOCAL_SHADOW
|
||||
this.phase = phase;
|
||||
this.inBufPos = inBufPos;
|
||||
#endif
|
||||
return nRead;
|
||||
}
|
||||
|
||||
private int ReadByteCore()
|
||||
{
|
||||
var buf = decodeBuffer;
|
||||
|
||||
if (inBufPos == inBufEnd)
|
||||
{
|
||||
int nRead = input.Read(buf, DecBufLen,
|
||||
InBufLen < inputLength ? InBufLen : (int)inputLength);
|
||||
|
||||
#if CHECK_EOF
|
||||
if (nRead == 0)
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
inputLength -= nRead;
|
||||
|
||||
inBufPos = DecBufLen;
|
||||
inBufEnd = DecBufLen + nRead;
|
||||
}
|
||||
|
||||
return buf[inBufPos++];
|
||||
}
|
||||
|
||||
private int ReadOffsetCore()
|
||||
{
|
||||
var buf = decodeBuffer;
|
||||
|
||||
if (inBufPos == inBufEnd)
|
||||
{
|
||||
int nRead = input.Read(buf, DecBufLen,
|
||||
InBufLen < inputLength ? InBufLen : (int)inputLength);
|
||||
|
||||
#if CHECK_EOF
|
||||
if (nRead == 0)
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
inputLength -= nRead;
|
||||
|
||||
inBufPos = DecBufLen;
|
||||
inBufEnd = DecBufLen + nRead;
|
||||
}
|
||||
|
||||
if (inBufEnd - inBufPos == 1)
|
||||
{
|
||||
buf[DecBufLen] = buf[inBufPos];
|
||||
|
||||
int nRead = input.Read(buf, DecBufLen + 1,
|
||||
InBufLen - 1 < inputLength ? InBufLen - 1 : (int)inputLength);
|
||||
|
||||
#if CHECK_EOF
|
||||
if (nRead == 0)
|
||||
{
|
||||
inBufPos = DecBufLen;
|
||||
inBufEnd = DecBufLen + 1;
|
||||
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
inputLength -= nRead;
|
||||
|
||||
inBufPos = DecBufLen;
|
||||
inBufEnd = DecBufLen + nRead + 1;
|
||||
}
|
||||
|
||||
int ret = (buf[inBufPos + 1] << 8) | buf[inBufPos];
|
||||
inBufPos += 2;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private int ReadCore(byte[] buffer, int offset, int count)
|
||||
{
|
||||
int nToRead = count;
|
||||
|
||||
var buf = decodeBuffer;
|
||||
int inBufLen = inBufEnd - inBufPos;
|
||||
|
||||
int fromBuf = nToRead < inBufLen ? nToRead : inBufLen;
|
||||
if (fromBuf != 0)
|
||||
{
|
||||
var bufPos = inBufPos;
|
||||
|
||||
for (int c = fromBuf; c-- != 0;)
|
||||
buffer[offset++] = buf[bufPos++];
|
||||
|
||||
inBufPos = bufPos;
|
||||
nToRead -= fromBuf;
|
||||
}
|
||||
|
||||
if (nToRead != 0)
|
||||
{
|
||||
int nRead;
|
||||
|
||||
if (nToRead >= InBufLen)
|
||||
{
|
||||
nRead = input.Read(buffer, offset,
|
||||
nToRead < inputLength ? nToRead : (int)inputLength);
|
||||
nToRead -= nRead;
|
||||
}
|
||||
else
|
||||
{
|
||||
nRead = input.Read(buf, DecBufLen,
|
||||
InBufLen < inputLength ? InBufLen : (int)inputLength);
|
||||
|
||||
inBufPos = DecBufLen;
|
||||
inBufEnd = DecBufLen + nRead;
|
||||
|
||||
fromBuf = nToRead < nRead ? nToRead : nRead;
|
||||
|
||||
var bufPos = inBufPos;
|
||||
|
||||
for (int c = fromBuf; c-- != 0;)
|
||||
buffer[offset++] = buf[bufPos++];
|
||||
|
||||
inBufPos = bufPos;
|
||||
nToRead -= fromBuf;
|
||||
}
|
||||
|
||||
inputLength -= nRead;
|
||||
}
|
||||
|
||||
return count - nToRead;
|
||||
}
|
||||
|
||||
#region Stream internals
|
||||
|
||||
public override bool CanRead => true;
|
||||
|
||||
public override bool CanSeek => false;
|
||||
|
||||
public override bool CanWrite => false;
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
}
|
||||
|
||||
public override long Length => throw new NotSupportedException();
|
||||
|
||||
public override long Position
|
||||
{
|
||||
get => throw new NotSupportedException();
|
||||
set => throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -131,7 +131,7 @@ namespace Il2CppDumper
|
|||
}
|
||||
}
|
||||
}
|
||||
if (version == 24)
|
||||
if (version >= 24)
|
||||
{
|
||||
/* ADRP X0, unk
|
||||
* ADD X0, X0, unk
|
||||
|
|
222
Il2CppDumper/NSO.cs
Normal file
222
Il2CppDumper/NSO.cs
Normal file
|
@ -0,0 +1,222 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Lz4;
|
||||
|
||||
namespace Il2CppDumper
|
||||
{
|
||||
public sealed class NSO : Il2Cpp
|
||||
{
|
||||
private NSOHeader header;
|
||||
private bool isTextCompressed;
|
||||
private bool isRoDataCompressed;
|
||||
private bool isDataCompressed;
|
||||
private List<NSOSegmentHeader> segments = new List<NSOSegmentHeader>();
|
||||
private bool isCompressed => isTextCompressed || isRoDataCompressed || isDataCompressed;
|
||||
|
||||
|
||||
public NSO(Stream stream, float version, long maxMetadataUsages) : base(stream, version, maxMetadataUsages)
|
||||
{
|
||||
header = new NSOHeader();
|
||||
header.Magic = ReadUInt32();
|
||||
header.Version = ReadUInt32();
|
||||
header.Reserved = ReadUInt32();
|
||||
header.Flags = ReadUInt32();
|
||||
isTextCompressed = (header.Flags & 1) != 0;
|
||||
isRoDataCompressed = (header.Flags & 2) != 0;
|
||||
isDataCompressed = (header.Flags & 4) != 0;
|
||||
header.TextSegment = new NSOSegmentHeader
|
||||
{
|
||||
FileOffset = ReadUInt32(),
|
||||
MemoryOffset = ReadUInt32(),
|
||||
DecompressedSize = ReadUInt32()
|
||||
};
|
||||
segments.Add(header.TextSegment);
|
||||
header.ModuleOffset = ReadUInt32();
|
||||
header.RoDataSegment = new NSOSegmentHeader
|
||||
{
|
||||
FileOffset = ReadUInt32(),
|
||||
MemoryOffset = ReadUInt32(),
|
||||
DecompressedSize = ReadUInt32()
|
||||
};
|
||||
segments.Add(header.RoDataSegment);
|
||||
header.ModuleFileSize = ReadUInt32();
|
||||
header.DataSegment = new NSOSegmentHeader
|
||||
{
|
||||
FileOffset = ReadUInt32(),
|
||||
MemoryOffset = ReadUInt32(),
|
||||
DecompressedSize = ReadUInt32()
|
||||
};
|
||||
segments.Add(header.DataSegment);
|
||||
header.BssSize = ReadUInt32();
|
||||
header.DigestBuildID = ReadBytes(0x20);
|
||||
header.TextCompressedSize = ReadUInt32();
|
||||
header.RoDataCompressedSize = ReadUInt32();
|
||||
header.DataCompressedSize = ReadUInt32();
|
||||
header.Padding = ReadBytes(0x1C);
|
||||
header.APIInfo = new NSORelativeExtent
|
||||
{
|
||||
RegionRoDataOffset = ReadUInt32(),
|
||||
RegionSize = ReadUInt32()
|
||||
};
|
||||
header.DynStr = new NSORelativeExtent
|
||||
{
|
||||
RegionRoDataOffset = ReadUInt32(),
|
||||
RegionSize = ReadUInt32()
|
||||
};
|
||||
header.DynSym = new NSORelativeExtent
|
||||
{
|
||||
RegionRoDataOffset = ReadUInt32(),
|
||||
RegionSize = ReadUInt32()
|
||||
};
|
||||
header.TextHash = ReadBytes(0x20);
|
||||
header.RoDataHash = ReadBytes(0x20);
|
||||
header.DataHash = ReadBytes(0x20);
|
||||
|
||||
if (!isCompressed)
|
||||
{
|
||||
Position = header.TextSegment.FileOffset + 4;
|
||||
var modOffset = ReadInt32();
|
||||
Position = header.TextSegment.FileOffset + modOffset + 8;
|
||||
var bssStart = ReadUInt32();
|
||||
var bssEnd = ReadUInt32();
|
||||
header.BssSegment = new NSOSegmentHeader
|
||||
{
|
||||
FileOffset = bssStart,
|
||||
MemoryOffset = bssStart,
|
||||
DecompressedSize = bssEnd - bssStart
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public override dynamic MapVATR(dynamic uiAddr)
|
||||
{
|
||||
var segment = segments.First(x => uiAddr >= x.MemoryOffset && uiAddr <= x.MemoryOffset + x.DecompressedSize);
|
||||
return uiAddr - segment.MemoryOffset + segment.FileOffset;
|
||||
}
|
||||
|
||||
public override bool Search()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool AdvancedSearch(int methodCount)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool PlusSearch(int methodCount, int typeDefinitionsCount)
|
||||
{
|
||||
var plusSearch = new PlusSearch(this, methodCount, typeDefinitionsCount, maxMetadataUsages);
|
||||
plusSearch.SetSearch(header.DataSegment);
|
||||
plusSearch.SetPointerRangeFirst(header.DataSegment);
|
||||
plusSearch.SetPointerRangeSecond(header.TextSegment);
|
||||
var codeRegistration = plusSearch.FindCodeRegistration64Bit();
|
||||
plusSearch.SetPointerRangeSecond(header.BssSegment);
|
||||
var metadataRegistration = plusSearch.FindMetadataRegistration64Bit();
|
||||
if (codeRegistration != 0 && metadataRegistration != 0)
|
||||
{
|
||||
Console.WriteLine("CodeRegistration : {0:x}", codeRegistration);
|
||||
Console.WriteLine("MetadataRegistration : {0:x}", metadataRegistration);
|
||||
Init(codeRegistration, metadataRegistration);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool SymbolSearch()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public NSO UnCompress()
|
||||
{
|
||||
if (isTextCompressed || isRoDataCompressed || isDataCompressed)
|
||||
{
|
||||
var unCompressedStream = new MemoryStream();
|
||||
var writer = new BinaryWriter(unCompressedStream);
|
||||
writer.Write(header.Magic);
|
||||
writer.Write(header.Version);
|
||||
writer.Write(header.Reserved);
|
||||
writer.Write(0); //Flags
|
||||
writer.Write(header.TextSegment.FileOffset);
|
||||
writer.Write(header.TextSegment.MemoryOffset);
|
||||
writer.Write(header.TextSegment.DecompressedSize);
|
||||
writer.Write(header.ModuleOffset);
|
||||
var roOffset = header.TextSegment.FileOffset + header.TextSegment.DecompressedSize;
|
||||
writer.Write(roOffset); //header.RoDataSegment.FileOffset
|
||||
writer.Write(header.RoDataSegment.MemoryOffset);
|
||||
writer.Write(header.RoDataSegment.DecompressedSize);
|
||||
writer.Write(header.ModuleFileSize);
|
||||
writer.Write(roOffset + header.RoDataSegment.DecompressedSize); //header.DataSegment.FileOffset
|
||||
writer.Write(header.DataSegment.MemoryOffset);
|
||||
writer.Write(header.DataSegment.DecompressedSize);
|
||||
writer.Write(header.BssSize);
|
||||
writer.Write(header.DigestBuildID);
|
||||
writer.Write(header.TextCompressedSize);
|
||||
writer.Write(header.RoDataCompressedSize);
|
||||
writer.Write(header.DataCompressedSize);
|
||||
writer.Write(header.Padding);
|
||||
writer.Write(header.APIInfo.RegionRoDataOffset);
|
||||
writer.Write(header.APIInfo.RegionSize);
|
||||
writer.Write(header.DynStr.RegionRoDataOffset);
|
||||
writer.Write(header.DynStr.RegionSize);
|
||||
writer.Write(header.DynSym.RegionRoDataOffset);
|
||||
writer.Write(header.DynSym.RegionSize);
|
||||
writer.Write(header.TextHash);
|
||||
writer.Write(header.RoDataHash);
|
||||
writer.Write(header.DataHash);
|
||||
writer.BaseStream.Position = header.TextSegment.FileOffset;
|
||||
Position = header.TextSegment.FileOffset;
|
||||
var textBytes = ReadBytes((int)header.TextCompressedSize);
|
||||
if (isTextCompressed)
|
||||
{
|
||||
var unCompressedData = new byte[header.TextSegment.DecompressedSize];
|
||||
using (var decoder = new Lz4DecoderStream(new MemoryStream(textBytes)))
|
||||
{
|
||||
decoder.Read(unCompressedData, 0, unCompressedData.Length);
|
||||
}
|
||||
writer.Write(unCompressedData);
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.Write(textBytes);
|
||||
}
|
||||
var roDataBytes = ReadBytes((int)header.RoDataCompressedSize);
|
||||
if (isRoDataCompressed)
|
||||
{
|
||||
var unCompressedData = new byte[header.RoDataSegment.DecompressedSize];
|
||||
using (var decoder = new Lz4DecoderStream(new MemoryStream(roDataBytes)))
|
||||
{
|
||||
decoder.Read(unCompressedData, 0, unCompressedData.Length);
|
||||
}
|
||||
writer.Write(unCompressedData);
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.Write(roDataBytes);
|
||||
}
|
||||
var dataBytes = ReadBytes((int)header.DataCompressedSize);
|
||||
if (isDataCompressed)
|
||||
{
|
||||
var unCompressedData = new byte[header.DataSegment.DecompressedSize];
|
||||
using (var decoder = new Lz4DecoderStream(new MemoryStream(dataBytes)))
|
||||
{
|
||||
decoder.Read(unCompressedData, 0, unCompressedData.Length);
|
||||
}
|
||||
writer.Write(unCompressedData);
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.Write(dataBytes);
|
||||
}
|
||||
writer.Flush();
|
||||
unCompressedStream.Position = 0;
|
||||
return new NSO(unCompressedStream, version, maxMetadataUsages);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
47
Il2CppDumper/NSOClass.cs
Normal file
47
Il2CppDumper/NSOClass.cs
Normal file
|
@ -0,0 +1,47 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Il2CppDumper
|
||||
{
|
||||
public class NSOHeader
|
||||
{
|
||||
public uint Magic;
|
||||
public uint Version;
|
||||
public uint Reserved;
|
||||
public uint Flags;
|
||||
public NSOSegmentHeader TextSegment;
|
||||
public uint ModuleOffset;
|
||||
public NSOSegmentHeader RoDataSegment;
|
||||
public uint ModuleFileSize;
|
||||
public NSOSegmentHeader DataSegment;
|
||||
public uint BssSize;
|
||||
public byte[] DigestBuildID;
|
||||
public uint TextCompressedSize;
|
||||
public uint RoDataCompressedSize;
|
||||
public uint DataCompressedSize;
|
||||
public byte[] Padding;
|
||||
public NSORelativeExtent APIInfo;
|
||||
public NSORelativeExtent DynStr;
|
||||
public NSORelativeExtent DynSym;
|
||||
public byte[] TextHash;
|
||||
public byte[] RoDataHash;
|
||||
public byte[] DataHash;
|
||||
|
||||
public NSOSegmentHeader BssSegment;
|
||||
}
|
||||
|
||||
public class NSOSegmentHeader
|
||||
{
|
||||
public uint FileOffset;
|
||||
public uint MemoryOffset;
|
||||
public uint DecompressedSize;
|
||||
}
|
||||
|
||||
public class NSORelativeExtent
|
||||
{
|
||||
public uint RegionRoDataOffset;
|
||||
public uint RegionSize;
|
||||
}
|
||||
}
|
|
@ -1,7 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Il2CppDumper
|
||||
{
|
||||
|
@ -142,6 +140,22 @@ namespace Il2CppDumper
|
|||
}
|
||||
}
|
||||
|
||||
public void SetSearch(params NSOSegmentHeader[] sections)
|
||||
{
|
||||
foreach (var section in sections)
|
||||
{
|
||||
if (section != null)
|
||||
{
|
||||
search.Add(new Section
|
||||
{
|
||||
start = section.FileOffset,
|
||||
end = section.FileOffset + section.DecompressedSize,
|
||||
address = section.MemoryOffset
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SetPointerRangeFirst(params MachoSection64Bit[] sections)
|
||||
{
|
||||
foreach (var section in sections)
|
||||
|
@ -254,6 +268,22 @@ namespace Il2CppDumper
|
|||
}
|
||||
}
|
||||
|
||||
public void SetPointerRangeFirst(params NSOSegmentHeader[] sections)
|
||||
{
|
||||
foreach (var section in sections)
|
||||
{
|
||||
if (section != null)
|
||||
{
|
||||
pointerRange1.Add(new Section
|
||||
{
|
||||
start = section.FileOffset,
|
||||
end = section.FileOffset + section.DecompressedSize,
|
||||
address = section.MemoryOffset
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SetPointerRangeSecond(params MachoSection64Bit[] sections)
|
||||
{
|
||||
pointerRange2.Clear();
|
||||
|
@ -390,6 +420,23 @@ namespace Il2CppDumper
|
|||
}
|
||||
}
|
||||
|
||||
public void SetPointerRangeSecond(params NSOSegmentHeader[] sections)
|
||||
{
|
||||
pointerRange2.Clear();
|
||||
foreach (var section in sections)
|
||||
{
|
||||
if (section != null)
|
||||
{
|
||||
pointerRange2.Add(new Section
|
||||
{
|
||||
start = section.MemoryOffset,
|
||||
end = section.MemoryOffset + section.DecompressedSize,
|
||||
address = section.MemoryOffset
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ulong FindCodeRegistration()
|
||||
{
|
||||
foreach (var section in search)
|
||||
|
|
|
@ -119,21 +119,26 @@ namespace Il2CppDumper
|
|||
var isElf = false;
|
||||
var isPE = false;
|
||||
var is64bit = false;
|
||||
var isNSO = false;
|
||||
switch (il2cppMagic)
|
||||
{
|
||||
default:
|
||||
throw new Exception("ERROR: il2cpp file not supported.");
|
||||
case 0x304F534E:
|
||||
isNSO = true;
|
||||
is64bit = true;
|
||||
break;
|
||||
case 0x905A4D: //PE
|
||||
isPE = true;
|
||||
break;
|
||||
case 0x464c457f: //ELF
|
||||
isElf = true;
|
||||
if (il2cppBytes[4] == 2)
|
||||
if (il2cppBytes[4] == 2) //ELF64
|
||||
{
|
||||
goto case 0xFEEDFACF; //ELF64
|
||||
is64bit = true;
|
||||
}
|
||||
break;
|
||||
case 0xCAFEBABE: //FAT header
|
||||
case 0xCAFEBABE: //FAT Mach-O
|
||||
case 0xBEBAFECA:
|
||||
var machofat = new MachoFat(new MemoryStream(il2cppBytes));
|
||||
Console.Write("Select Platform: ");
|
||||
|
@ -147,14 +152,14 @@ namespace Il2CppDumper
|
|||
var index = int.Parse(key.KeyChar.ToString()) - 1;
|
||||
var magic = machofat.fats[index % 2].magic;
|
||||
il2cppBytes = machofat.GetMacho(index % 2);
|
||||
if (magic == 0xFEEDFACF) // 64-bit mach object file
|
||||
if (magic == 0xFEEDFACF)
|
||||
goto case 0xFEEDFACF;
|
||||
else
|
||||
goto case 0xFEEDFACE;
|
||||
case 0xFEEDFACF: // 64-bit mach object file
|
||||
case 0xFEEDFACF: // 64bit Mach-O
|
||||
is64bit = true;
|
||||
break;
|
||||
case 0xFEEDFACE: // 32-bit mach object file
|
||||
case 0xFEEDFACE: // 32bit Mach-O
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -162,7 +167,12 @@ namespace Il2CppDumper
|
|||
var modeKey = Console.ReadKey(true);
|
||||
var version = config.ForceIl2CppVersion ? config.ForceVersion : metadata.version;
|
||||
Console.WriteLine("Initializing il2cpp file...");
|
||||
if (isPE)
|
||||
if (isNSO)
|
||||
{
|
||||
var nso = new NSO(new MemoryStream(il2cppBytes), version, metadata.maxMetadataUsages);
|
||||
il2cpp = nso.UnCompress();
|
||||
}
|
||||
else if (isPE)
|
||||
{
|
||||
il2cpp = new PE(new MemoryStream(il2cppBytes), version, metadata.maxMetadataUsages);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue