0xAA55 发表于 2016-6-11 01:59:44

【VB】VB6+ASM写文件的SHA1哈希值计算工具



BIN下载:
要下载源代码请先回帖。**** Hidden Message *****

VB6用自己的加减乘除与或非进行位运算的话有个先天性不足:左移或右移难以实现。VB6的IDE有整数溢出检查,挺麻烦的。
然后SHA1的算法是需要做 leftrotate 运算的。所以要是用加减乘除来模拟左移和右移就会严重影响速度。因此我写了个Shellcode,用这个Shellcode完成SHA1的区块处理。bits 32

_SHA1_ProcChunk:

;        void*psrc // uint8_t src
;        uint32_t pstate

push esi
push edi

%define SizeOfTempVar (80*4+6*4)
%define OffsetToInitESP (SizeOfTempVar+8)
;Parameters
%define pSrcData_
%define pSHA1States_
;Local vars
%define WordBuf (esp+6*4)
%define A_
%define B_
%define C_
%define D_
%define E_
%define T_
%macro MovRegs 0
mov T_,eax
mov eax,D_
mov E_,eax
mov eax,C_
mov D_,eax
mov eax,B_
rol eax,30
mov C_,eax
mov eax,A_
mov B_,eax
mov eax,T_
mov A_,eax
%endmacro

;Allocate memory from stack
sub esp,SizeOfTempVar

;break chunk into sixteen 32-bit big-endian words w, 0 ≤ i ≤ 15
mov ecx,16
mov esi,pSrcData_
lea edi,
.InitWords:
lodsd
bswap eax
stosd
loop .InitWords

;Extend the sixteen 32-bit words into eighty 32-bit words:
;for i from 16 to 79
;    w = (w xor w xor w xor w) leftrotate 1
lea edi,
mov ecx,64
.InitAllWords:
mov eax,
xor eax,
xor eax,
xor eax,
rol eax,1
stosd
loop .InitAllWords

;Initialize hash value for this chunk:
;a = h0
;b = h1
;c = h2
;d = h3
;e = h4
mov esi,pSHA1States_
lea edi,A_
mov ecx,5
rep movsd

lea esi,

;========
mov ecx,20
.ProcStep1:
mov eax,B_
mov edx,eax
and eax,C_ ;B & C
not edx
and edx,D_ ;(~B) & D
or eax,edx ;(B & C) | ((~B) & D)
mov edx,A_
rol edx,5
add edx,eax ;+ rotateleft(A,5)
lodsd
add eax,edx ;+ W
add eax,E_;+ E
add eax,0x5A827999 ;+ K
MovRegs
loop .ProcStep1

;========
mov ecx,20
.ProcStep2:
mov eax,A_
rol eax,5;rorareleft(A,5)
mov edx,B_
xor edx,C_
xor edx,D_ ;B^C^D
add eax,E_
add edx,eax
lodsd
add eax,edx;+ W
add eax,0x6ED9EBA1;+ K
MovRegs
loop .ProcStep2

;========
mov ecx,20
.ProcStep3:
mov edx,B_
and edx,D_ ;B & D
mov eax,B_
and eax,C_ ;B & C
or edx,eax
mov eax,C_
and eax,D_ ;C & D
or edx,eax
mov eax,A_
rol eax,5;rorareleft(A,5)
add eax,E_
add edx,eax
lodsd
add eax,edx;+ W
add eax,0x8F1BBCDC;+ K
MovRegs
loop .ProcStep3

;========
mov ecx,20
.ProcStep4:
mov eax,A_
rol eax,5;rorareleft(A,5)
mov edx,B_
xor edx,C_
xor edx,D_ ;B^C^D
add eax,E_
add edx,eax
lodsd
add eax,edx;+ W
add eax,0xCA62C1D6;+ K
MovRegs
loop .ProcStep4

;Finished
mov edi,pSHA1States_
mov eax,A_
add ,eax
mov eax,B_
add ,eax
mov eax,C_
add ,eax
mov eax,D_
add ,eax
mov eax,E_
add ,eax

add esp,SizeOfTempVar

pop edi
pop esi
ret 16因为我打算用CallWindowProc来调用它,因此它其实是被当作LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);来调用的。但其实第一个参数是数据Chunk的指针,第二个参数是SHA1状态结构体(存储5个uint32_t)的指针。

Attribute VB_Name = "modSHA1"
Option Explicit

Type SHA1State_t
    h0 As Long
    h1 As Long
    h2 As Long
    h3 As Long
    h4 As Long
End Type

Private Declare Function CallProc4Param Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal Param1 As Long, ByVal Param2 As Long, ByVal Param3 As Long, ByVal Param4 As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Private Declare Sub ZeroMemory Lib "kernel32" Alias "RtlZeroMemory" (Dest As Any, ByVal numBytes As Long)
Private Declare Function GetSystemDefaultLCID Lib "kernel32" () As Long


Private m_Ops(121) As Long

Sub SHA1_Init(State As SHA1State_t)

m_Ops(0) = &HEC815756:   m_Ops(1) = &H158&:       m_Ops(2) = &H10B9&:      m_Ops(3) = &H24B48B00:   m_Ops(4) = &H164&
m_Ops(5) = &H18247C8D:   m_Ops(6) = &HABC80FAD:   m_Ops(7) = &H7C8DFAE2:   m_Ops(8) = &H40B95824:   m_Ops(9) = &H8B000000
m_Ops(10) = &H4733F447:m_Ops(11) = &HC84733E0:m_Ops(12) = &HD1C04733:m_Ops(13) = &HEFE2ABC0:m_Ops(14) = &H6824B48B
m_Ops(15) = &H8D000001:m_Ops(16) = &H5B9243C:   m_Ops(17) = &HF3000000:m_Ops(18) = &H24748DA5:m_Ops(19) = &H14B918
m_Ops(20) = &H448B0000:m_Ops(21) = &HC2890424:m_Ops(22) = &H8244423:   m_Ops(23) = &H5423D2F7:m_Ops(24) = &HD0090C24
m_Ops(25) = &HC124148B:m_Ops(26) = &HC20105C2:m_Ops(27) = &H3D001AD:   m_Ops(28) = &H5102444:   m_Ops(29) = &H5A827999
m_Ops(30) = &H14244489:m_Ops(31) = &HC24448B:   m_Ops(32) = &H10244489:m_Ops(33) = &H824448B:   m_Ops(34) = &HC244489
m_Ops(35) = &H424448B:   m_Ops(36) = &H891EC0C1:m_Ops(37) = &H8B082444:m_Ops(38) = &H44892404:m_Ops(39) = &H448B0424
m_Ops(40) = &H4891424:   m_Ops(41) = &HB9ABE224:m_Ops(42) = &H14&:       m_Ops(43) = &HC124048B:m_Ops(44) = &H548B05C0
m_Ops(45) = &H54330424:m_Ops(46) = &H54330824:m_Ops(47) = &H44030C24:m_Ops(48) = &HC2011024:m_Ops(49) = &H5D001AD
m_Ops(50) = &H6ED9EBA1:m_Ops(51) = &H14244489:m_Ops(52) = &HC24448B:   m_Ops(53) = &H10244489:m_Ops(54) = &H824448B
m_Ops(55) = &HC244489:   m_Ops(56) = &H424448B:   m_Ops(57) = &H891EC0C1:m_Ops(58) = &H8B082444:m_Ops(59) = &H44892404
m_Ops(60) = &H448B0424:m_Ops(61) = &H4891424:   m_Ops(62) = &HB9B1E224:m_Ops(63) = &H14&:       m_Ops(64) = &H424548B
m_Ops(65) = &HC245423:   m_Ops(66) = &H424448B:   m_Ops(67) = &H8244423:   m_Ops(68) = &H448BC209:m_Ops(69) = &H44230824
m_Ops(70) = &HC2090C24:m_Ops(71) = &HC124048B:m_Ops(72) = &H440305C0:m_Ops(73) = &HC2011024:m_Ops(74) = &H5D001AD
m_Ops(75) = &H8F1BBCDC:m_Ops(76) = &H14244489:m_Ops(77) = &HC24448B:   m_Ops(78) = &H10244489:m_Ops(79) = &H824448B
m_Ops(80) = &HC244489:   m_Ops(81) = &H424448B:   m_Ops(82) = &H891EC0C1:m_Ops(83) = &H8B082444:m_Ops(84) = &H44892404
m_Ops(85) = &H448B0424:m_Ops(86) = &H4891424:   m_Ops(87) = &HB9A1E224:m_Ops(88) = &H14&:       m_Ops(89) = &HC124048B
m_Ops(90) = &H548B05C0:m_Ops(91) = &H54330424:m_Ops(92) = &H54330824:m_Ops(93) = &H44030C24:m_Ops(94) = &HC2011024
m_Ops(95) = &H5D001AD:   m_Ops(96) = &HCA62C1D6:m_Ops(97) = &H14244489:m_Ops(98) = &HC24448B:   m_Ops(99) = &H10244489
m_Ops(100) = &H824448B:m_Ops(101) = &HC244489:m_Ops(102) = &H424448B:m_Ops(103) = &H891EC0C1: m_Ops(104) = &H8B082444
m_Ops(105) = &H44892404: m_Ops(106) = &H448B0424: m_Ops(107) = &H4891424:m_Ops(108) = &H8BB1E224: m_Ops(109) = &H16824BC
m_Ops(110) = &H48B0000:m_Ops(111) = &H8B070124: m_Ops(112) = &H1042444:m_Ops(113) = &H448B0447: m_Ops(114) = &H47010824
m_Ops(115) = &H24448B08: m_Ops(116) = &HC47010C:m_Ops(117) = &H1024448B: m_Ops(118) = &H81104701: m_Ops(119) = &H158C4
m_Ops(120) = &HC25E5F00: m_Ops(121) = &H10&

State.h0 = &H67452301
State.h1 = &HEFCDAB89
State.h2 = &H98BADCFE
State.h3 = &H10325476
State.h4 = &HC3D2E1F0

Int64_InitGlobal
End Sub

'读取sha1.bin并在立即窗口打印数组
'Sub SHA1_LoadOps()
'Dim Ops() As Long
'Open App.Path & "\sha1.bin" For Binary Access Read As #1
'ReDim Ops(LOF(1) \ 4)
'Get #1, , Ops
'Close #1
'
'Dim I&, X&
'For I = 0 To UBound(Ops)
'    X = X + 1
'    If X > 4 Then
'      Debug.Print "m_Ops("; CStr(I); ") = &H"; Hex$(Ops(I)); "&"
'      X = 0
'    Else
'      Debug.Print "m_Ops("; CStr(I); ") = &H"; Hex$(Ops(I)); "&:";
'    End If
'Next
'End Sub

'处理每个64字节区块
Sub SHA1_ProcChunk(State As SHA1State_t, ByVal ChunkPtr As Long)
CallProc4Param VarPtr(m_Ops(0)), ChunkPtr, VarPtr(State), 0, 0
End Sub

'处理最后一个区块
Sub SHA1_ProcLastChunk(State As SHA1State_t, ByVal LastDataPtr As Long, ByVal cbLastData As Long, cbTotal As Int64_t)
Dim Padded(63) As Byte
Dim BETotalBits As Int64_t

'规则:
'在数据的最后一个字节后面添加一个0x80
'总数据用0补足为64字节的N倍大小
'将数据最后的8个字节替换成,数据的总bits的Big-Ending顺序方式存储
'然后做一次区块计算

BETotalBits = cbTotal
Int64_Shl BETotalBits, 3 'Bytes * 8
Int64_BSWAP BETotalBits

If cbLastData + 9 <= 64 Then
    CopyMemory Padded(0), ByVal LastDataPtr, cbLastData
    Padded(cbLastData) = &H80 'Last bit
    CopyMemory Padded(56), BETotalBits, 8
    SHA1_ProcChunk State, VarPtr(Padded(0))
ElseIf cbLastData = 64 Then
    SHA1_ProcChunk State, LastDataPtr
    Padded(0) = &H80
    CopyMemory Padded(56), BETotalBits, 8
    SHA1_ProcChunk State, VarPtr(Padded(0))
Else
    CopyMemory Padded(0), ByVal LastDataPtr, cbLastData
    Padded(cbLastData) = &H80'Last bit
    SHA1_ProcChunk State, VarPtr(Padded(0))
   
    ZeroMemory Padded(0), 64
    CopyMemory Padded(56), BETotalBits, 8
    SHA1_ProcChunk State, VarPtr(Padded(0))
End If
End Sub

'将处理后的5个寄存器输出为字符串
Function SHA1_GetResultStr(State As SHA1State_t) As String
SHA1_GetResultStr = Hex32(State.h0) & Hex32(State.h1) & Hex32(State.h2) & Hex32(State.h3) & Hex32(State.h4)
End Function

'数字转换为用0补足的8位十六进制数字字符串
Private Function Hex32(ByVal Num As Long) As String
Hex32 = Right$("0000000" & Hex$(Num), 8)
End Function

'计算字符串的SHA1值
Function SHA1_CalcStringSHA1(ByVal StrToCalc As String, Optional ByVal LocaleID As Long) As String
Dim MBArr() As Byte, cbMBArr As Int64_t
If LocaleID = 0 Then LocaleID = GetSystemDefaultLCID
MBArr = StrConv(StrToCalc, vbFromUnicode, LocaleID)
cbMBArr.L = UBound(MBArr) + 1

Dim State As SHA1State_t, I&
SHA1_Init State
Do While I + 64 < cbMBArr.L
    SHA1_ProcChunk State, VarPtr(MBArr(I))
    I = I + 64
Loop
SHA1_ProcLastChunk State, VarPtr(MBArr(I)), cbMBArr.L - I, cbMBArr
SHA1_CalcStringSHA1 = SHA1_GetResultStr(State)
End Function

Function SHA1_CalcFileSHA1(ByVal FilePath As String) As String
Dim Chunk(63) As Byte, FileLen As Long
Dim ChunkLen As Int64_t
Dim SHA1State As SHA1State_t

SHA1_Init SHA1State

ChunkLen.L = 64

Dim FO As File_t
If File_OpenForRead(FilePath, FO) = False Then GoTo ErrHandler
Dim RestLen As Int64_t

RestLen = FO.Size

Do While RestLen.H <> 0 Or RestLen.L > 64
    File_Read FO, VarPtr(Chunk(0)), 64
    SHA1_ProcChunk SHA1State, VarPtr(Chunk(0))
    Int64_Sub RestLen, ChunkLen
Loop

File_Read FO, VarPtr(Chunk(0)), RestLen.L
SHA1_ProcLastChunk SHA1State, VarPtr(Chunk(0)), RestLen.L, FO.Size
File_Close FO
SHA1_CalcFileSHA1 = SHA1_GetResultStr(SHA1State)

Exit Function
ErrHandler:
File_Close FO
SHA1_CalcFileSHA1 = "Calc SHA1 failed."
End Function

'Sub SHA1_Test()
'Dim Blank(63) As Byte
'Blank(0) = &H80
'
'Dim State As SHA1State_t
'
'SHA1_Init State
'SHA1_ProcChunk State, VarPtr(Blank(0))
'Debug.Print SHA1_GetResultStr(State)
'Debug.Print "DA39A3EE5E6B4B0D3255BFEF95601890AFD80709 - 0 byte"
'End Sub

SHA1的详细算法,请参考以下文章:
https://en.wikipedia.org/wiki/SHA-1
http://www.mattmahoney.net/dc/sha1.c


submariner 发表于 2016-10-24 09:00:37

这个看起来很赞

jasonchen 发表于 2016-11-17 10:30:21

支持    !!

olalala 发表于 2016-11-20 02:17:24

好好学习天天向上

songxudong 发表于 2017-1-9 12:33:07

不错的东西,谢谢楼主分享

songxudong 发表于 2017-1-9 12:33:31

不错的东西谢谢楼主分享

冷清 发表于 2017-3-18 01:05:43

刚开始学习。

冷清 发表于 2017-3-18 01:13:20

老哥,我发现,选择大文件就会崩溃。。

besteast 发表于 2017-3-22 20:28:04

:(:(:(:(:(:(:(

oshi 发表于 2017-7-24 07:03:25

先回复一下,看看里面的内容.

0xAA55 发表于 2017-9-2 12:58:10

这是一个手动用汇编写无栈帧函数的实例,给局部变量从栈上分配内存+使用esp对参数和局部变量进行寻址等。
用了宏把偏移的计算自动化了。
有栈帧便于调试,代码也好写,不过栈帧本身对于运行而言是可有可无的。
其实优不优化栈帧意义不大。

bigwind 发表于 2017-9-19 18:01:29

VB】VB6+ASM写文件的SHA1哈希值计算工具

oshi 发表于 2017-9-27 08:08:26

先回复一下先.

搬砖工 发表于 2018-9-15 00:42:38

看看汇编怎么做

kx25 发表于 2018-11-19 22:44:01

不错,正需要这个!!!!

xiongsx 发表于 2020-1-15 15:19:12

学习一下

系统消息 发表于 2020-1-15 20:15:21

感觉VB6直接用WinAPI来算就够了

hxin123456 发表于 2020-4-3 21:02:55

看看学习下

唐凌 发表于 2020-7-4 22:54:31

可以考虑用sha扩展指令集重写一下asm,把sha1rnds4, sha1nexte, sha1msg1, sha1msg2指令代进来。
需要检测cpuid.ebx置位。

0xAA55 发表于 2020-7-5 08:05:13

tangptr@126.com 发表于 2020-7-4 22:54
可以考虑用sha扩展指令集重写一下asm,把sha1rnds4, sha1nexte, sha1msg1, sha1msg2指令代进来。
需要检测c ...

在这之前我需要把文件IO改成支持超4G大文件流式读取的那种
页: [1] 2
查看完整版本: 【VB】VB6+ASM写文件的SHA1哈希值计算工具