⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vmp3d.asm

📁 Cracker终结者——提供最优秀的软件保护技术
💻 ASM
📖 第 1 页 / 共 2 页
字号:
;/////////////////////////////////////////////////////////////////////////////
;// vmp3d.asm
;//
;// Virtual MPEG Audio Layer3 Device module (link with MP3 Decoder module)
;//
;// 25/10/1999	fOSSiL		Initial version
;// 12/11/1999	fOSSiL		Switched to VPICD_Get_Version start-point
;//				and added better fault-recovery
;// 2000/01/15	The Owl		nasm port
;// 2000/01/16	The Owl		started to add playing related services
;// 2000/01/17	Fossil		fixed Trace_Out macros, intersegment relocs
;// 2000/01/17	The Owl		fixed bugs introduced in the nasm port ;-)
;// 2000/01/18	The Owl		added services
;// 2000/01/20	The Owl		rewrote MMSYSTEM and AppyTime event handling
;// 2000/01/21	The Owl		fixed VMP3D_Play_Prev/Next
;// 2000/01/28	The Owl		init fails properly when VDSPD doesn't load
;// 2000/06/21	The Owl		dword aligned data variables


%include "util.mac"
%include "vxdn.inc"
%include "win32n.inc"
%include "vpicdi.inc"
%include "dma.inc"
%include "mp3dec.inc"
%include "vdspd.inc"
%include "fpu.inc"

%define Create_Service_Table_VMP3D
%include "vmp3d.inc"


global VMP3D_Control


bits 32


segment _LDATA

Declare_Virtual_Device VMP3D, 'VMP3D', 1, 0, VMP3D_Device_ID


segment _LTEXT
Begin_Control_Dispatch VMP3D
	Control_Dispatch DEVICE_INIT,VMP3D_Device_Init
	Control_Dispatch SYS_DYNAMIC_DEVICE_INIT,VMP3D_Device_Init
	Control_Dispatch SYS_DYNAMIC_DEVICE_EXIT,VMP3D_Device_Exit
	Control_Dispatch W32_DEVICEIOCONTROL,VMP3D_W32_DeviceIoControl
End_Control_Dispatch


WAVE_FORMAT_PCM	EQU	1

struc WaveFormatEx
wfmt_wFormatTag		resw 1
wfmt_nChannels		resw 1
wfmt_nSamplesPerSec	resd 1
wfmt_nAvgBytesPerSec	resd 1
wfmt_nBlockAlign	resw 1
wfmt_wBitsPerSample	resw 1
endstruc


;
; Global Data
;
segment _LDATA
	align 4
Owner		dd 0
IsPlaying	db 0

	align 4
OrgHwIntProc	dd 0
OrgMaskIRQProc	dd 0

DmaPhysAddr	dd 0
DmaLinAddr	dd 0

IrqNum		dd 0
PicReg		db 0
PicMask		db 0

	align 4
;VID		VPICD_IRQ_Descriptor <5, VPICD_OPT_CAN_SHARE, DspHwIntProc>
IrqTab		dd 0
hIrq		dd 0
hDma		dd 0

FileSize	dd 0
FileLeft	dd 0
BufAddr		dd 0
BufPtr		dd 0

cBlocks		dd 0
CurBlock	dd 0

ListBuf		dd 0
ListPages	dd 0
NextFile	dd 0

MpegBuf		dd 0
MpegPtr		dd 0
MpegLastBytes	dd 0


segment _SDATA
hMMLib		dd 0
_hMMSem		dd 0
waveOutOpen	dd 0
waveOutClose	dd 0
hMMmem		dd 0
LinMMmem	dd 0
IsBusy		dd 0


segment _LDATA
MMwfe:
istruc WaveFormatEx
  at wfmt_wFormatTag,		dw WAVE_FORMAT_PCM
  at wfmt_nChannels,		dw 1
  at wfmt_nSamplesPerSec,	dd 22050
  at wfmt_nAvgBytesPerSec,	dd 22050
  at wfmt_nBlockAlign,		dw 1
  at wfmt_wBitsPerSample,	dw 8
iend
hMMWave		dw 0

segment _LDATA
LastFrame:
istruc FrameInfo
iend


;
; Services
;
segment _LTEXT
VMP3D_Device_Init:
; load DSP vxd
	mov	edx, devname
	mov	eax, VXDLDR_INIT_DEVICE
	VxDCall	VXDLDR_LoadDevice
	jnc	.dsploaded

	cmp	eax, byte VXDLDR_ERR_DUPLICATE_DEVICE
	jz	.dsploaded

%if ADD_DEBUG = 1
	Trace_Out "VDSPD did not load, code #EAX"
%endif

	stc
	retn

.dsploaded:
; Allocate a 64k DMA buffer for DSP
	mov	edx, DmaPhysAddr

; we need mem below 16Meg
; pages=16
; PG_SYS, VM=0
; align=64k
; minpage=0
; maxpage=1000h
; &Dma.PhysAddr
; PAGECONTIG|PAGEUSEALIGN|PAGEFIXED
	VMMCall	_PageAllocate, byte 16, byte PG_SYS, byte 0, byte 0fh, byte 0, dword 1000h, edx, dword PAGECONTIG + PAGEUSEALIGN + PAGEFIXED
	cmp	eax, byte 0
	jnz	@F

%if ADD_DEBUG = 1
	Trace_Out "DMA buffer not alloced"
%endif

	stc
	retn

@@
	mov	[DmaLinAddr], eax

; Allocate a static MPEG buffer (8000h+2000h)
	VMMCall	_PageAllocate, byte 10, byte PG_SYS, byte 0, byte 0, byte 0, byte 0, byte 0, dword PAGEFIXED
	cmp	eax, byte 0
	jnz	@F

%if ADD_DEBUG = 1
	Trace_Out "MPEG buffer not alloced"
%endif

	jmp	.cleanup1

@@
	mov	[MpegBuf], eax

; lookup VPICD irq tables
; we will lookup VPICD_Get_Version address,
; basing on the assumption that Get_Version is close
; to Virtualize_IRQ service
; and scan code from there for a specific MOV opcode
; (hopefully no one will hook Get_Version service)
	mov	eax, VPICD_Device_ID
	VMMCall	Get_DDB

	cmp	ecx, byte 0
	jnz	@F

%if ADD_DEBUG = 1
	Trace_Out "Get_DBB failed"
%endif
	jmp	.cleanup2

@@
	mov	edi, [ecx + DDB_Service_Table_Ptr]
	mov	edi, dword [edi + (@@VPICD_Get_Version & 0xFFFF)*4]
	
; look for mov esi,<mem>[ecx*4] opcode
	mov	ecx, 1000h
	mov	al, 8bh

.again:
	repne	scasb

%if ADD_DEBUG = 1
	Trace_OutNE "MOV pattern not found"
%endif

	jne	near .cleanup2

	cmp	word [edi], 8d34h
	jne	.again

	mov	edi, [edi+2]	; get irq table addr
	cmp	edi, 0C0000000h	; lame check, but at least something
	jb	near .cleanup3

; hopefully, this is the table of IRQStruct ptrs
	mov	[IrqTab], edi

	mov	edi, [edi]	; check table layout through IRQ0's structs
	cmp	edi, 0C0000000h	; lame check, but at least something
	jb	near .cleanup3

	mov	eax, [edi + VID_IRQCB.hIrqOwner]
	cmp	eax, 0C0000000h	; lame check, but at least something
	jb	.cleanup3

	cmp	dword [eax + VID_IRQ_Struct.DbgStr], 51524953h	; 'SIRQ'
	jne	.cleanup3

; init MPEG decoder
	push	dword ReadStreamData
	call	_MpegSetReadProc@4

; init AppyTime synchronization semaphore and load MMSYSTEM
	cmp	dword [hMMLib], byte 0
	jne	@F

	VxDCall	_SHELL_CallAtAppyTime, dword AppyLoadMMLib, byte 0, byte 0, byte 0

	cmp	eax, byte 0
	jne	@F

%if ADD_DEBUG = 1
	Trace_Out "Init appy event-schedule failed"
%endif

	jmp	short .cleanup2

@@
;	cmp	dword [hMMSem], byte 0
;	jne	@F
;
;	xor	ecx, ecx
;	VMMCall	Create_Semaphore
;
;%if ADD_DEBUG = 1
;	Trace_OutC "MM Semaphore not created"
;%endif
;
;	jc	.cleanup2
;
;	mov	[hMMSem], eax
;
;@@

%if ADD_DEBUG = 1
	Trace_Out "MP3 vxd init success"
%endif

	clc
	retn

.cleanup3:
%if ADD_DEBUG = 1
	Trace_Out "MOV pattern found, but VPICD structs are invalid or of unknown format"
%endif

.cleanup2:
; free MPEG buffer
	VMMCall	_PageFree, dword [MpegBuf], byte 0

.cleanup1:
; free DMA buffer
	VMMCall	_PageFree, dword [DmaLinAddr], byte 0

	stc
	retn


segment _LDATA
devname	db 'vdspd.vxd',0


segment _LTEXT
AppyLoadMMLib:
; PROC C Public, dwRefData:DWORD, dwFlags:DWORD
	cmp	dword [hMMLib], byte 0
	je	@F

%if ADD_DEBUG = 1
	Trace_Out "MMSYSTEM already loaded"
%endif

	retn

@@
	VxDCall	_SHELL_LoadLibrary, dword libname

	cmp	eax, byte 32
	jae	@F

%if ADD_DEBUG = 1
	Trace_Out "MMSYSTEM did not load, code #EAX"
%endif

	retn

@@
	mov	[hMMLib], eax

	VxDCall _SHELL_GetProcAddress, dword [hMMLib], dword fnopen
	mov	[waveOutOpen], eax

	VxDCall _SHELL_GetProcAddress, dword [hMMLib], dword fnclose
	mov	[waveOutClose], eax

	VxDCall	_SHELL_LocalAllocEx, byte LMEM_FIXED, byte WaveFormatEx_size + 2, dword MMwfe

	cmp	eax, byte 0
	jne	@F

%if ADD_DEBUG = 1
	Trace_Out "Cannot alloc 16bit mem"
%endif

	retn

@@
	mov	[hMMmem], eax
	mov	[LinMMmem], edx

%if ADD_DEBUG = 1
	Trace_Out "MMSYSTEM loaded at AppyTime"
%endif

	retn


segment _LDATA
libname	db 'MMSYSTEM',0
fnopen	db 'WAVEOUTOPEN',0
fnclose	db 'WAVEOUTCLOSE',0


segment _LTEXT
VMP3D_Device_Exit:
; cleanup DMA buffer
	VMMCall	_PageFree, dword [DmaLinAddr], byte 0
	VMMCall	_PageFree, dword [ListBuf], byte 0
	VMMCall	_PageFree, dword [MpegBuf], byte 0
	xor	eax, eax
	clc
	retn


;segment _PTEXT	; nasm intersegment relocs in same object are bad,
		; better keep this in _LTEXT for now
;
; Win32 DeviceIoControl Dispatcher
;
VMP3D_W32_DeviceIoControl:
	mov	ecx, [esi + DIOCParams.dwIoControlCode]
	mov	ebx, [esi + DIOCParams.VMHandle]
	mov	ebp, [esi + DIOCParams.Internal1]

	cmp	ecx, byte DIOC_OPEN
	jnz	@F

	cmp	dword [Owner], byte 0

%if ADD_DEBUG = 1
	Trace_OutNE "Device is already owned"
%endif
	jne	.err			; another VM has it
	    
	mov	[Owner], ebx

	VxDCall VDSPD_Get_IRQ
	call	HookIrq

%if ADD_DEBUG = 1
	  Trace_OutC "HookIrq failed"
%endif
	jc	.err

	xor	eax, eax
	retn

@@
	cmp	ecx, byte DIOC_CLOSEHANDLE
	jnz	@F

	mov	eax, 1			; release wave dev
	call	StopMpeg
	call	UnhookIrq
	
	mov	dword [Owner], 0

	xor	eax, eax
	retn

@@
; get Function #
	and	ecx, 0x3FFC

	cmp	ecx,byte 4*10
	ja	.err

	jmp	[W32_API+ecx]

.err:
	cmp	eax, byte 1	; eax cannot be == 0 on error
	sbb	eax, byte 0
	retn


segment _LDATA
	align 4
W32_API:
	dd VMP3D_W32_DeviceIoControl.err
	dd VMP3D_W32_DeviceIoControl.err	; W32_PlayWave
	dd W32_SetList
	dd W32_Play
	dd W32_Stop
	dd W32_Pause
	dd W32_Resume
	dd W32_GetMpegInfo
	dd W32_GetStreamPtr
	dd W32_SetStreamPtr
	dd W32_GetStatusInfo


segment _LTEXT
W32_SetRetCode:
;Assume	esi:PTR DIOCParams
	cmp	dword [esi + DIOCParams.cbOutBuffer], byte 4
	jae	@F

	retn

@@
	mov	ecx, [esi + DIOCParams.lpvOutBuffer]	; write to out-buf
	cmp	ecx, byte 0
	jz	@F

	mov	[ecx], eax
	
@@
	mov	ecx, [esi + DIOCParams.lpcbBytesReturned] ; write # of bytes returned
	cmp	ecx, byte 0
	jz	@F

	mov	dword [ecx], 4

@@
	retn


W32_SetList:
;Assume	esi:PTR DIOCParams
	or	eax, byte -1
	mov	edx, [esi + DIOCParams.cbInBuffer]
	cmp	edx, byte 4
	jae	@F

	retn

@@
	mov	edi, [esi + DIOCParams.lpvInBuffer]
	cmp	edi, byte 0
	jnz	@F

	retn

@@
	bts	dword [IsBusy], 0
	jnc	@F

	retn

@@
	add	edx, 0fffh
	shr	edx, 12
	cmp	edx, [ListPages]
	jbe	.norealloc

	mov	[ListPages], edx
	VMMCall	_PageFree, dword [ListBuf], byte 0
	VMMCall	_PageAllocate, dword [ListPages], byte PG_SYS, byte 0, byte 0, byte 0, byte 0, byte 0, dword PAGEFIXED
	cmp	eax, byte 0
	jnz	@F

%if ADD_DEBUG = 1
	Trace_OutZ "List buffer not alloced"
%endif

	jmp	short .err1

@@
	mov	[ListBuf], eax

.norealloc:
; copy list
	mov	ecx, [esi + DIOCParams.cbInBuffer]
	push	esi
	mov	esi, [ListBuf]
	xchg	esi, edi
	rep	movsb
	pop	esi
	
; update ptrs
	mov	edi, [ListBuf]
	mov	edx, edi
	mov	ecx, [edi]
	add	edi, byte 4

@@
	add	[edi], edx
	add	edi, byte 4
	loop	@B
	
	mov	dword [NextFile], 0

	xor	eax, eax

.svcret1:
	call	W32_SetRetCode
	btr	dword [IsBusy], 0
	retn

.err1:
	cmp	eax, byte 1
	sbb	eax, byte 0
	jmp	short .svcret1


W32_Play:
;Assume	esi:PTR DIOCParams
	or	eax, byte -1
	cmp	dword [esi + DIOCParams.cbInBuffer], byte 4
	jae	@F

	retn

@@
	mov	edi, [esi + DIOCParams.lpvInBuffer]
	cmp	edi, byte 0
	jnz	@F

	retn

@@
	bts	dword [IsBusy], 0
	jnc	@F

	retn

@@
	mov	eax, [edi]
	call	SetIndex
	jc	@F

	call	PlayMpegIndex
	jc	@F

	xor	eax, eax

@@
	call	W32_SetRetCode
	btr	dword [IsBusy], 0
	retn


W32_Stop:
;Assume	esi:PTR DIOCParams
	or	eax, byte -1
	cmp	byte [IsPlaying], 0
	jz	@F

	bts	dword [IsBusy], 0
	jc	@F

	mov	eax, 1
	call	StopMpeg
	xor	eax, eax

	btr	dword [IsBusy], 0

@@
	call	W32_SetRetCode
	retn


W32_Pause:
;Assume	esi:PTR DIOCParams
	or	eax, byte -1
	cmp	byte [IsPlaying], 0
	jz	@F

	VxDCall	VDSPD_Pause
	mov	eax, -1
	jc	@F

	xor	eax, eax

@@
	call	W32_SetRetCode
	retn


W32_Resume:
;Assume	esi:PTR DIOCParams
	or	eax, byte -1
	cmp	byte [IsPlaying], 0
	jz	@F

	VxDCall	VDSPD_Resume
	mov	eax, -1
	jc	@F

	xor	eax, eax

@@
	call	W32_SetRetCode
	retn


W32_GetStreamPtr:
;Assume	esi:PTR DIOCParams
	or	eax, byte -1
	cmp	byte [IsPlaying], 0
	jz	@F

	mov	eax, [BufPtr]

@@
	call	W32_SetRetCode

	cmp	eax, byte 0
	jl	@F		; error

	xor	eax, eax

@@
	retn


W32_SetStreamPtr:
;Assume	esi:PTR DIOCParams
	mov	edi, [esi + DIOCParams.lpvInBuffer]
	or	eax, byte -1
	cmp	dword [esi + DIOCParams.cbInBuffer], byte 4
	jb	@F

	cmp	edi, byte 0
	jz	@F

	cmp	byte [IsPlaying], 0
	jz	@F

	bts	dword [IsBusy], 0
	jc	@F

	mov	eax, [edi]
	call	SetPtr

	btr	dword [IsBusy], 0

@@
	call	W32_SetRetCode
	retn


W32_GetMpegInfo:
;Assume	esi:PTR DIOCParams
	mov	edi, [esi + DIOCParams.lpvOutBuffer]
;Assume	edi:PTR MpegInfo

	or	eax, byte -1
	cmp	dword [esi + DIOCParams.cbOutBuffer], byte MpegInfo_size
	jb	@F

	cmp	edi, byte 0
	jz	@F

	cmp	byte [IsPlaying], 0
	jz	@F

	push	esi
	push	edi
	add	edi, byte 4			; sizeof MpegInfo.RetCode
	mov	ecx, (MpegInfo_size - 4) / 4
	mov	esi, LastFrame
	rep	movsd
	pop	edi
	pop	esi
	mov	eax, [FileSize]
	mov	[edi + MpegInfo.StreamSize], eax

	xor	eax, eax
	
@@
	call	W32_SetRetCode
	mov	ecx, [esi + DIOCParams.lpcbBytesReturned] ; write # of bytes returned
	cmp	eax, byte 0
	jnz	@F

	cmp	ecx, byte 0
	jz	@F

	mov	dword [ecx], MpegInfo_size

@@
	retn


W32_GetStatusInfo:
	or	eax, byte -1
	cmp	dword [esi + DIOCParams.cbOutBuffer], byte StatusInfo_size
	jb	.setretcode

	mov	edi, [esi + DIOCParams.lpvOutBuffer]
	test	edi, edi
	jz	.setretcode

	push	dword [NextFile]
	pop	dword [edi+StatusInfo.Track]

	push	dword [BufPtr]
	pop	dword [edi+StatusInfo.Progress],

	mov	al,[IsPlaying]
	mov	[edi+StatusInfo.IsPlaying], al

	mov	al,[IsBusy]
	mov	[edi+StatusInfo.IsBusy], al

	xor	eax, eax

.setretcode:
	call	W32_SetRetCode
	mov	ecx, [esi + DIOCParams.lpcbBytesReturned] ; write # of bytes returned

	cmp	eax, byte 0
	jnz	@F

	cmp	ecx, byte 0
	jz	@F

	mov	dword [ecx], StatusInfo_size

@@
	retn


segment _LTEXT
SetPtr:
; EAX = index
	cmp	eax, [FileSize]
	jb	@F

	or	eax, byte -1
	stc
	retn

@@
; no interruptions now, please =)
	pushfd
	cli
	mov	[BufPtr], eax
	mov	ecx, [FileSize]
	sub	ecx, eax
	mov	[FileLeft], ecx
	popfd

	xor	eax, eax
	clc
	retn


StopMpeg:
; EAX = 1 : release wave device
	cmp	byte [IsPlaying], 1
	jnz	@F

	VxDCall	VDSPD_Stop
	mov	byte [IsPlaying], 0

@@
	cmp	eax, byte 1
	jnz	@F

	cmp	word [hMMWave], 0
	jz	@F

	VxDCall _SHELL_CallAtAppyTime, dword AppyWaveClose, byte 0, byte 0, byte 0
	cmp	eax, byte 0

%if ADD_DEBUG = 1
	Trace_OutE "Let-go Wave appy event-schedule failed"
%endif

	jz	@F

;	mov	eax, [hMMSem]
;	mov	ecx, BLOCK_SVC_INTS | BLOCK_ENABLE_INTS
;	VMMCall	Wait_Semaphore
	VMMCall	_BlockOnID, dword hMMLib, dword BLOCK_SVC_INTS | BLOCK_ENABLE_INTS

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -