📄 dns.asm
字号:
; DNS Client, only MX records are supported
; #########################################################################
.data
bDNSLoaded db 0
.const
;============
; Iphlpapi.h
;============
MAX_HOSTNAME_LEN equ 128
MAX_DOMAIN_NAME_LEN equ 128
MAX_SCOPE_ID_LEN equ 256
; The FIXED_INFO structure contains information that is the same across all the interfaces in a computer.
IP_ADDR_STRING struct
Next DWORD ?
IpAddress BYTE 16 dup(?)
IpMask BYTE 16 dup(?)
Context DWORD ?
IP_ADDR_STRING ends
FIXED_INFO struct
HostName BYTE MAX_HOSTNAME_LEN+4 dup(?) ; Host name for the local computer.
DomainName BYTE MAX_DOMAIN_NAME_LEN+4 dup(?) ; Domain in which the local computer is registered.
CurrentDnsServer DWORD ? ; Reserved. Use the DnsServerList member to obtain the DNS servers for the local computer.
DnsServerList IP_ADDR_STRING <> ; Linked list of IP_ADDR_STRING structures that specify the set of DNS servers used by the local computer.
NodeType DWORD ? ; Node type of the local computer.
ScopeId BYTE MAX_SCOPE_ID_LEN+4 dup(?) ; DHCP scope name.
EnableRouting DWORD ? ; Specifies whether routing is enabled on the local computer.
EnableProxy DWORD ? ; Specifies whether the local computer is acting as an ARP proxy.
EnableDns DWORD ? ; Specifies whether DNS is enabled on the local computer.
FIXED_INFO ends
;===========
; DNS types
;===========
; RR types
TYPE_A equ 1 ; Host address
TYPE_NS equ 2 ; Authorative name server
TYPE_MD equ 3 ; Mail destination
TYPE_MF equ 4 ; Mail forwarder
TYPE_CNAME equ 5 ; Canonical name of an alias
TYPE_SOA equ 6 ; Marks the start of a zone of authority
TYPE_MB equ 7 ; Mailbox domain name (Experimental)
TYPE_MG equ 8 ; Mail group member (Experimental)
TYPE_MR equ 9 ; Mail rename domain name (Experimental)
TYPE_NULL equ 10 ; Null RR (Experimental)
TYPE_WKS equ 11 ; Will known service description
TYPE_PTR equ 12 ; Domain name pointer
TYPE_HINFO equ 13 ; Host information
TYPE_MINFO equ 14 ; Mailbox or mail list information
TYPE_MX equ 15 ; Mail exchange
TYPE_TXT equ 16 ; Text strings
TYPE_RP equ 17 ; Responsible person (Experimental)
TYPE_AFSDB equ 18 ; Andrew File System Data Base (Experimental)
TYPE_X25 equ 19 ; X.25 address (Experimental)
TYPE_ISDN equ 20 ; Integrated Services Digital Network addresses (Experimental)
TYPE_RT equ 21 ; Route Through (Experimental)
; Classes
CLASS_IN equ 1 ; Internet class
CLASS_CS equ 2 ; CSNET class
CLASS_CH equ 3 ; CHAOS class
CLASS_HS equ 4 ; Hesiod
RECURSIZE_REQUEST equ 256
DNS_HEADER struct
ID WORD ?
OPCODE WORD ?
QDCOUNT WORD ?
ANCOUNT WORD ?
NSCOUNT WORD ?
ARCOUNT WORD ?
DNS_HEADER ends
.code
; Get localy saved DNS server
DNSGetServer proc
LOCAL pFixedInfo, pOutBufLen: DWORD
invoke GlobalAlloc, GPTR, sizeof FIXED_INFO
mov pFixedInfo, eax
mov pOutBufLen, sizeof FIXED_INFO
lea eax, pOutBufLen
push eax
push pFixedInfo
call dwGetNetworkParams
.IF eax == ERROR_BUFFER_OVERFLOW
invoke GlobalFree, pFixedInfo
invoke GlobalAlloc, GPTR, pOutBufLen
mov pFixedInfo, eax
.ENDIF
lea eax, pOutBufLen
push eax
push pFixedInfo
call dwGetNetworkParams
.IF !eax
mov eax, pFixedInfo
assume eax: ptr FIXED_INFO
invoke lstrcpy, offset szDNSHost, addr [eax].DnsServerList.IpAddress
.ENDIF
invoke GlobalFree, pFixedInfo
ret
DNSGetServer endp
DNSHandleRequest proto :DWORD ; forward
; Prepare MX record query
DNSQuery proc uses esi edi ebx stream, szHost: DWORD
LOCAL header: DNS_HEADER
LOCAL pbyte: DWORD
LOCAL bword: WORD
invoke ZeroMemory, addr header, sizeof header
mov header.ID, 0202h
mov header.OPCODE, RECURSIZE_REQUEST
ror header.OPCODE, 8
mov header.QDCOUNT, 1
ror header.QDCOUNT, 8
coinvoke stream, IStream, Write, addr header, sizeof header, 0
; Write host
invoke lstrlen, szHost
mov ecx, eax
mov edi, szHost
@l:
mov edx, edi
mov al, '.'
cld
repnz scasb
mov ebx, edi
sub ebx, edx
.IF byte ptr[edi-1] == '.'
dec ebx
.ENDIF
mov pbyte, ebx
push ecx
push edx
coinvoke stream, IStream, Write, addr pbyte, 1, 0
pop ecx
coinvoke stream, IStream, Write, ecx, pbyte, 0
mov pbyte, 0
pop ecx
test ecx, ecx
jnz @l
; Zero terminator
coinvoke stream, IStream, Write, addr pbyte, 1, 0
; Type
mov bword, TYPE_MX
ror bword, 8
coinvoke stream, IStream, Write, addr bword, 2, 0
; Class
mov bword, CLASS_IN
ror bword, 8
coinvoke stream, IStream, Write, addr bword, 2, 0
ret
DNSQuery endp
; Send request, receive response, returns MX server on success, otherwise NULL
DNSRequest proc uses ebx stream, szDNSServer: DWORD
LOCAL len: DWORD
LOCAL lpbuf[128]: BYTE
mov ecx, DNSPort
xchg cl, ch
invoke NetConnect, szDNSServer, 0, ecx
.IF eax
mov ebx, eax
invoke StreamGetLength, stream
xchg al, ah
mov len, eax
invoke send, ebx, addr len, 2, 0
invoke StreamGotoBegin, stream
@l:
coinvoke stream, IStream, Read, addr lpbuf, 128, addr len
.IF len
invoke send, ebx, addr lpbuf, len, 0
jmp @l
.ENDIF
invoke StreamClear, stream
invoke NetRecvUntilBytes, ebx, stream, 2, 4, 0
test eax, eax
jz @close_sock
invoke StreamGotoBegin, stream
mov len, 0
coinvoke stream, IStream, Read, addr len, 2, 0
invoke StreamClear, stream
mov eax, len
xchg al, ah
invoke NetRecvUntilBytes, ebx, stream, eax, 4, 0
test eax, eax
jz @close_sock
invoke closesocket, ebx
invoke DNSHandleRequest, stream
mov ebx, eax
invoke lstrlen, eax
.IF !eax
; Empty string
invoke GlobalFree, ebx
xor eax, eax
.ELSE
mov eax, ebx
.ENDIF
ret
@close_sock:
invoke closesocket, ebx
.ENDIF
xor eax, eax
ret
DNSRequest endp
; Read compressed string chunk and append it to strmem
DNSReadChunk proc uses esi edi basemem, mem, strmem: DWORD
mov esi, mem
@next_read:
cld
xor eax, eax
lodsb
test al, 11000000b
.IF !ZERO?
and al, 00111111b
shl ax, 8
; Second octet of the offset
lodsb
push esi
mov esi, basemem
add esi, eax
invoke DNSReadChunk, basemem, esi, strmem
pop esi
.ELSEIF al
push eax
invoke lstrlen, strmem
mov edi, strmem
add edi, eax
pop ecx
jecxz @no_cpe_str
cld
rep movsb
@no_cpe_str:
mov al, '.'
stosb
xor eax, eax
stosb
jmp @next_read
.ENDIF
mov eax, esi
ret
DNSReadChunk endp
; Read compressed string
DNSReadString proc basemem, mem, strmem: DWORD
szText DNSTrimChars, "."
mov eax, strmem
mov byte ptr[eax], 0
invoke DNSReadChunk, basemem, mem, strmem
push eax
invoke StrTrim, strmem, offset DNSTrimChars
pop eax
ret
DNSReadString endp
; Handles only MX records, returns string with MX server on success
; Otherwise returned string consists from NULL terminator only
DNSHandleRequest proc uses esi edi ebx stream: DWORD
LOCAL hMem, hStr, hStr2: DWORD
LOCAL pref: WORD
mov pref, 65535 ; MX PREFERENCE
invoke GlobalAlloc, GMEM_FIXED, 65536
mov hStr, eax
invoke GlobalAlloc, GMEM_FIXED, 65536
mov byte ptr[eax], 0
mov hStr2, eax
invoke StreamGetLength, stream
mov ebx, eax
invoke GlobalAlloc, GMEM_FIXED, eax
mov hMem, eax
invoke StreamGotoBegin, stream
coinvoke stream, IStream, Read, hMem, ebx, 0
mov esi, hMem
assume esi: ptr DNS_HEADER
ror [esi].ANCOUNT, 8
ror [esi].OPCODE, 8
test [esi].OPCODE, 1111b
.IF !ZERO?
jmp @yep_the_error
.ENDIF
movzx ebx, [esi].ANCOUNT
add esi, sizeof DNS_HEADER
; Skip question
invoke DNSReadString, hMem, esi, hStr
mov esi, eax
lodsd ; Type & Class
.IF eax != 01000f00h
jmp @yep_the_error
.ENDIF
; Read answer
.IF ebx
@read_answer:
invoke DNSReadString, hMem, esi, hStr
mov esi, eax
lodsd ; Type, Class
push eax
lodsd ; TTL
xor eax, eax
lodsw ; RDLENGTH
pop edx
.IF edx != 01000f00h
; RDATA(Unknown), skip
xchg al, ah
add esi, eax
.ELSE
; RDATA(MX)
lodsw ; PREFERENCE
push ax
invoke DNSReadString, hMem, esi, hStr
mov esi, eax
pop dx
; Store MX host
.IF dx < pref
mov pref, dx
invoke lstrcpy, hStr2, hStr
.ENDIF
.ENDIF
dec ebx
jnz @read_answer
.ENDIF
@yep_the_error:
invoke GlobalFree, hMem
invoke GlobalFree, hStr
mov eax, hStr2
ret
DNSHandleRequest endp
; Retrieves MX record for szBaseHost, returns null terminated
; host on success, otherwise null
DNSGetMXHost proc szBaseHost: DWORD
LOCAL stream: DWORD
.IF !bDNSLoaded
mov bDNSLoaded, 1
.IF dwGetNetworkParams
invoke DNSGetServer
.ENDIF
.ENDIF
invoke StreamCreate, addr stream
invoke DNSQuery, stream, szBaseHost
invoke DNSRequest, stream, offset szDNSHost
push eax
invoke StreamFree, stream
pop eax
ret
DNSGetMXHost endp
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -