using System.IO.Compression; using System.Text; namespace JiDangJia.Server; // Reads Android's binary XML without extracting or executing uploaded files. internal sealed record ApkManifest(string PackageId,int VersionCode,string VersionName) { public static ApkManifest Read(string path) { using var zip=ZipFile.OpenRead(path);var entry=zip.GetEntry("AndroidManifest.xml")??throw new ArgumentException("请选择完整的 APK 安装包"); if(entry.Length is <8 or >2097152||zip.GetEntry("classes.dex") is null)throw new ArgumentException("APK 内容无效"); using var stream=entry.Open();using var buffer=new MemoryStream();var block=new byte[8192];int read;while((read=stream.Read(block))>0){if(buffer.Length+read>2097152)throw new InvalidDataException();buffer.Write(block,0,read);}byte[] bytes=buffer.ToArray(); int U16(int p){if(p<0||p>bytes.Length-2)throw new InvalidDataException();return BitConverter.ToUInt16(bytes,p);} uint U32(int p){if(p<0||p>bytes.Length-4)throw new InvalidDataException();return BitConverter.ToUInt32(bytes,p);} var strings=new List();long decodedSize=0;string S(uint index)=>indexbytes.Length-p)throw new InvalidDataException("APK 清单损坏"); if(type==1) { int count=checked((int)U32(p+8)),start=checked((int)U32(p+20));bool utf8=(U32(p+16)&256)!=0; if(count<0||count>100000||header+4L*count>size)throw new InvalidDataException(); for(int i=0;i=p+size)throw new InvalidDataException();int length; if(utf8) { int Len(){if(q>=p+size)throw new InvalidDataException();int n=bytes[q++];if((n&128)!=0){if(q>=p+size)throw new InvalidDataException();n=((n&127)<<8)|bytes[q++];}return n;} Len();length=Len();decodedSize+=length;if(length>p+size-q||decodedSize>4194304)throw new InvalidDataException();strings.Add(Encoding.UTF8.GetString(bytes,q,length)); } else {length=U16(q);q+=2;if((length&32768)!=0){length=((length&32767)<<16)|U16(q);q+=2;}int n=checked(length*2);decodedSize+=n;if(n>p+size-q||decodedSize>4194304)throw new InvalidDataException();strings.Add(Encoding.Unicode.GetString(bytes,q,n));} } } else if(type==0x102&&S(U32(p+20))=="manifest") { int attr=p+16+U16(p+24),stride=U16(p+26),count=U16(p+28);if(stride<20||attr+count*(long)stride>p+size)throw new InvalidDataException(); string package="",name="";int version=0; for(int i=0;i200||version<=0||name.Length is <1 or >80)throw new ArgumentException("APK 缺少应用或版本信息");return new(package,version,name); } p+=size; } throw new ArgumentException("APK 缺少应用清单"); } }