@@ -14,8 +14,6 @@ class PeFile {
1414 private val _signData : DataInfo
1515 private val _dotnetMetadata : DataInfo
1616
17- private val RawPeData : ByteArray by lazy { rawPeData() }
18-
1917 val ImageDirectoryEntrySecurityOffset : Int
2018 get() = _imageDirectoryEntrySecurity .Offset
2119
@@ -108,48 +106,63 @@ class PeFile {
108106 * @param algName Name of the hashing algorithm
109107 * */
110108 fun ComputeHash (@NotNull algName : String ): ByteArray {
111- val data = RawPeData
112109 val hash = MessageDigest .getInstance(algName)
113110
114- // hash from start to checksum field
111+ fun hashRange (startOffset : Long , length : Long ) {
112+ if (length <= 0L ) return
113+ val fileSize = _stream .size()
114+ val safeStart = startOffset.coerceAtLeast(0L ).coerceAtMost(fileSize)
115+ val maxLen = (fileSize - safeStart).coerceAtLeast(0L )
116+ val safeLen = length.coerceAtMost(maxLen)
117+ if (safeLen <= 0L ) return
118+
119+ val buffer = ByteArray (1024 * 1024 ) // 1MB chunks
120+ var remaining = safeLen
121+ _stream .Seek (safeStart, SeekOrigin .Begin )
122+ while (remaining > 0 ) {
123+ val toRead = if (remaining < buffer.size) remaining.toInt() else buffer.size
124+ val bytesRead = _stream .read(java.nio.ByteBuffer .wrap(buffer, 0 , toRead))
125+ if (bytesRead <= 0 ) break
126+ hash.update(buffer, 0 , bytesRead)
127+ remaining - = bytesRead
128+ }
129+ }
130+
131+ val fileSize = _stream .size().toInt()
132+
133+ // 1) Hash from start to checksum field (exclusive)
115134 var offset = 0
116135 var count = _checkSum .Offset
117- hash.update(data, offset, count)
136+ hashRange(offset.toLong(), count.toLong() )
118137
119- // jump over checksum and hash to IMAGE_DIRECTORY_ENTRY_SECURITY
138+ // 2) Skip checksum field, hash up to IMAGE_DIRECTORY_ENTRY_SECURITY (exclusive)
120139 offset = count + _checkSum .Size
121140 count = _imageDirectoryEntrySecurity .Offset - offset
122- hash.update(data, offset, count)
141+ hashRange(offset.toLong(), count.toLong() )
123142
124- // jump over IMAGE_DIRECTORY_ENTRY_SECURITY
143+ // 3) Skip IMAGE_DIRECTORY_ENTRY_SECURITY itself (8 bytes)
125144 offset = _imageDirectoryEntrySecurity .Offset + _imageDirectoryEntrySecurity .Size
126145
127- if (_signData .IsEmpty ) // PE is not signed
128- {
129- // hash to EOF
130- count = data.count() - offset
131- hash.update(data, offset, count)
146+ if (_signData .IsEmpty ) {
147+ // 4a) Not signed: hash to EOF
148+ count = fileSize - offset
149+ hashRange(offset.toLong(), count.toLong())
132150 } else {
133- // PE is signed
151+ // 4b) Signed: hash up to the start of signature data
134152 count = _signData .Offset - offset
153+ if (offset + count <= fileSize) {
154+ hashRange(offset.toLong(), count.toLong())
155+ }
135156
136- // hash to start the signature data
137- if ((offset + count) <= data.count())
138- hash.update(data, offset, count)
139-
140- // jump over the signature data and hash all the rest
157+ // 5) Jump over signature data and hash the rest to EOF
141158 offset = _signData .Offset + _signData .Size
142- count = data.count() - offset
143-
144- if (count > 0 )
145- hash.update(data, offset, count)
159+ count = fileSize - offset
160+ if (count > 0 ) {
161+ hashRange(offset.toLong(), count.toLong() )
162+ }
146163 }
147164
148165 return hash.digest()
149166 }
150-
151- private fun rawPeData (): ByteArray {
152- return _stream .Rewind ().ReadToEnd ()
153- }
154167}
155168
0 commit comments