Self-deletion of executable

xiaoxiao2021-03-06  59

VB has always been considered to have the following advantages and disadvantages: the advantage is fast, high development efficiency; the disadvantage is limited, and the operating efficiency is low. VB has a lot of people from other languages, do not support pointers, not supported, and inline assembly, etc., etc. When we enjoy the simple VB, we find that our space is getting smaller and smaller. Indeed, the simple and powerful, the two itself is a pair of contradictions. It's afraid that a line of code is not written, just start running an empty form, which is simple to operate, and VB will make a lot of complex work for us underneath (it is not only the registration window, the display window, the start message loop is so simple), and These tasks are transparent to programmers. Since I have limited level, and the restriction of related hardware (my desktop CPU is still PII450, only Win2000), the following conclusions are only valid for Win2000. Ok, start! We need software, VB6 SP6, anti-compilation software W32DSM89 (VC is also row); related knowledge: familiar with VB, it is best to know the pointers in C language, stack, of course, don't understand, don't matter, relevant knowledge author will give one one Explanation. One. Basic Concept 1, CopyMemory, such as CopyMemory, is defined in RTLMoveMemory in kernel32.dll This API, Memcpy in the 32-bit C library is this API package. Its function is to copy the length of the length of the length of the Source pointer to the memory referred to in Destination. It doesn't take care of our programs to read the permissions you should have in the memory, one, when it wants to read the memory protected by the system, we will get the famous Access Violation Fault (Memory Visual Visual Error), even It will cause more famous General Protection (GP) Fault (General Protection Error). So, when conducting the experiments in this series, please pay attention to your program files at any time, set the "Environment" tab in the "Tool" -> Options "in the VB integration environment. To "save changes", remember to save our work results before performing dangerous code in the Immediate window.

2, Vatptr / Strptr They are the baby provided to us, they are hidden functions in the VBA library. Varptr Returns the address of the variable, and StrPtr returns the address of the Unicode character array of BSTR points to the BSTR. The BSTR will be explained in detail below. Suppose the variable STR is located at the address AAAA, and this character array is at address xxxx, which is the content of the variable STR. In order to see the following: Varptr = aaaa strptr = xxxx We just run the following code: DIM LNG AS Long Dim i AS Integer Dim S AS String Dim B (1 TO 10) AS BYTE DIM SP AS Long, VP As long s = "Help" sp = strptr (s) debug.print "strptr:" & sp vp = varptr (s) debug.print "Varptr:" & VP

'Verify VP = AAAA and SP = XXXX COPYMEMORY LNG, BYVAL VP, 4 Debug.print LNG = SP' View the address of the character array contained in the SP, copy one byte array from that address and prints CopyMemory B (1), byval SP 10 for i = 1 to 10 debug.print B (i) Next I output results: strptr = xxxx varptr = aaa true 104 0 101 0 108 0 112 0 0 0

Why hide Vatptr / Strptr? Because the VB Development Team does not encourage us to use pointers. The following is a Varptr function looks like a C and assembly language: It is like this: Long Varptr (VOID * PV) {Return (long) PV;} Two lines: MOV Eax, DWORD PTR [ESP 4] RET 4 'pops up the value of the parameters in the stack and returns. The reason why everyone knows Varptr's specific implementation is to tell you that its overhead is not big because they have two instructions, even if they add parameter assignment, stack, and call instructions, the entire acquisition pointer will have six instructions. Of course, the same function is in the C language, only one instruction is required due to the direct support of the language. But in VB, it is already the fastest function, so we don't have to worry about using Varptr to make us lose efficiency! Speed ​​is the fundamental requirement using pointer technology. In one sentence, Varptr returns the memory address where the variable is located, or it is also necessary to return a pointer to the variable memory location, which is one of our most important weapons in VB.

3, the parameter value passed by byval and byrefByval, and the address of the parameter passed by Byref. In general procedures, we are very concerned about the difference between the two, even if the parameter address is delivered, it does not affect the value of the assignment statement in the code. But in some API applications, the typical application to Byval applications is CopyMemory. 'Experience BYVAL and BYREF SUB TestCopyMemory () DIM L AS Long L = 5Note: CopyMemory Byval Varptr (L), 40000, 4 Debug.print L End L End L End L End L End L End L End L End L End L End Sub The purpose of the statement at Note on the Load Note is 40000, equivalent In the statement L = 40000, you can experiment with the "Immediate" window, will find that the value of L is indeed 40000. In fact, this statement is translated into a whistle: ---------------------------------------- ------------------------ is copy 4 bytes from the transfer constant 40000 to the memory in the memory where the variable k is located. -------------------------------------------------- --------------- Now let's change the statement at Note, if it is changed to the following statement: Note2: CopyMemory Byval Varptr (L), Byval 40000, 4 this sentence It is formed, copies 4 bytes from the address 40000 to the memory where the variable L is located. Due to the memory of the address 40000 we have no right to access, the operating system will give us an Access Viocation memory access error, tell us "Attempt to read the location 0x00009C40 error, the memory cannot be 'read'." We changed to the following statement to see. Note3: CopyMemory Varptr (L), 40000, 4 The meaning of this sentence is made, and 4 bytes from the provisional variable from the save constant 40000 to the temporary variable of the memory address value where the variable k is located. This will not have memory access error, but the value of K has not changed. We can change the program to a clearer to resize this difference: 'Look at our things to have been copied to SUB TestCopyMemory () Dim i as long, l ask L = 5 i = varptr (l) Note4 : CopyMemory I, 40000, 4 Debug.print L Debug.print i i = varptr (L) Note5: CopyMemory Byval I, 40000, 4 Debug.print L End Sub Program Output: 54000040000 Due to Note4, the default byref is used The address of i (that is, the pointer to i), so the constant 40000 is copied into the variable I, so the value of I is 40000, and the value of L has not changed. However, before Note4: i = varptr (L), it is intended to use I itself as a pointer to use. At this time, we must use BYVAL as Note5 to deliver pointer i, since i is a pointer to the variable L, the last constant 40000 is copied in the variable L. I hope that you have understood this difference. In the discussion of the following questions, we will use the above concepts.

4. The stack performs the concept and analysis of parameter delivery in the process of subroutine calls. Generally in the program, the passage of the parameters is performed by the stack, that is, the caller presses the parameters to be passed to the subroutine (or the caller) into the stack, and the subroutine reuses the corresponding value in the stack, such as Say, if you want to call MessageBox (hwnd, lptext, lpcaption, uType), compiled final code may be: Push MB_OK PUSH OFFSET SZCAPTION PUSH OFFSET SZTEXT PUSH HWND CALL MESSAGEBOX TERYRED PUSH HWND CALL MESSAGEBOX T., the caller first presses the parameters into the stack, The subroutine is then called. After completion, the caller or the caller must have one to call the stack pointer to the status of the stack pointer to the status of the stack pointer due to the number of previously pressed in the stack. The parameter is the rightmost first in the stack or the leftmost first stack, and the caller is still a set of stacks, otherwise it will have an incorrect result, this is what I use "possibly" in front. " The reason for these two words: the convention for calling subroutines in various languages ​​is different. The default convention in C and VB is: stdcall, that is, in the API or subroutine, the rightmost parameter is first in the stack, then the child is responsible for calibrating the stack when returning. Look at the status of the child function / process is called: Parameter N (Nth Parameters, the rightmost parameter) ... Parameter 2 (2nd parameter) Parameter 1 (1st parameter) Return Address (Return address)

Second, the simulation of function pointer

VB can use the DecLare declaration to call the external function of the standard DLL, but its limitations are also obvious: using Declare we can only load the function pointer specified by the lib and alias words when designing! Instead of specifying a function pointer that is dynamically loaded by our own motion, you cannot use the declare statement to call any function pointer. When we want to dynamically call external functions, we must consider using other auxiliary methods to complete this task. The following is a VB call ASM that is taken from the Internet to implement the code and interpretation of the function pointer.

Principle: 1) Load DLL using LoadLibrary; 2) getProcAddress gets function pointer;

The pre-load function is obtained above, but the method of using this pointer is not provided in VB. We can complete the call of the function pointer through a compilation language!

3) Press all the parameters of the function into the stack by assembly language, and then use the Call to be used to use the function pointer.

The main procedures for implementing the above features: 'Loading Dllibaddr = LoadLibrary (Byval "User32")' Get function pointer procaddr = getProcadDress (libaddr, byval "messageboxa") 'prototype for MessageBox (hwnd, lptext, lpcaption, utype)

'- below assembly section --- Push Utypepush LPCAPTIONPUSH LPTEXTPUSH HWNDPUSH LPTEXTPUSH HWNDCALL PROCADDR' --------------------

Freeelibrary libraddr 'release space

Below is the source code of the MESSAGEBOXA. The above steps are encapsulated into the Rundll32 function, which can be placed in the module (CALLAPIBYNAME.BAS): DIM S1 () AS BYTE, S2 () AS BYTE DIM RET AS Long S1 = STRCONV ( "Hello ~ World", VBFromunicode S2 = STRCONV ("VBNote", VBFromunicode) RET = Rundll32 ("User32", "MessageBoxa", HWnd, Varptr (S1 (0)), Varptr (S2 (0)), 0 &) Sourcecodes in Callapibyname.bas:

Option expedition

Private Declare Function LoadLibrary Lib "kernel32" Alias ​​"LoadLibraryA" (ByVal lpLibFileName As String) As LongPrivate Declare Function GetProcAddress Lib "kernel32" (ByVal hModule As Long, ByVal lpProcName As String) As LongPrivate Declare Function CallWindowProc Lib "User32" Alias ​​"CallWindowProcA "(ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As LongPrivate Declare Function FreeLibrary Lib" kernel32 "(ByVal hLibModule As Long) As LongPrivate Declare Sub CopyMemory Lib" kernel32 "Alias" RTLMoveMemory "(LPDest as any, lpsource as any, byval cbytes as ring)

Public m_opindex as long 'write location private m_opcode () as byte' assembly Opcode

Public Function RunDll32 (LibFileName As String, ProcName As String, ParamArray Params ()) As Long Dim hProc As Long Dim hModule As Long ReDim m_OpCode (400 6 * UBound (Params)) 'reserved for write m_OpCode' read API library hModule = LoadLibrary (ByVal LibFileName) If hModule = 0 Then MsgBox "Library read failure!" Exit function End If 'acquired function address hProc = GetProcAddress (hModule, ByVal ProcName) If hProc = 0 Then MsgBox "function reads failed!" , Vbcritical Freelibrary HModule Exit Function End IF 'executing Assembly Code section Rundll32 = CallWindowProc (getCodestart (HProc, params), 0, 1, 2, 3) Freelibrary HModule' release space END FUNCTION

Private function getCodestart (Byval Arrparams as line, byval arrparams as variant) AS long '--- The following is the assembly section -' Role: Press the parameters of the function into the stack DIM LNGINDEX AS Long, LNGCODESTART AS Long 'start address Must be the multiple of the "Varptr function is used to get the address LNGCODESTART = (Varptr (m_opcode (0)) or & HF) 1 m_opIndex = LNGCODESTART - VARPTR (m_opcode (0)) 'program starting element of the element Part of the interrupt point is added to for lngindex = 0 to m_opindex - 1 m_opcode (lngindex) = & HCC 'int 3 next lngindex' ------- The following starts to put the required program ---------- - 'Because the parameter push to stack is to put the stdcall call parameter by the last start to put the stack for lngindex = ubound (arrparams) TO 0 Step -1 AddByTocode & H68' Push machine code is H68 AddlongTocode Clng (Arrparams (LNGIndex)) 'Parameter address Next LNGINDEX' CALL HPROC ADDBYTOCODE & HE8 'CALL machine code is HE8 AddlongTocode LNGPROC - Varptr (m_opcode (m_opIndex)) - 4' function address Address CALL address' --------- End Office Needable program -------------- 'Return Call Functions AddBytetocode & HC2' RET 10h AddByTocode & H10 AddBytetocode & H0 getCodestart = LNGCODESTERTEND FUNCTI OnPrivate Sub AddlongTocode (LDATA As Long) Writes the parameters of the long type to m_opcode CopyMemory M_opcode (M_opIndex), LDATA, 4 m_opIndex = m_opIndex 4END SUB

Private Sub AddintTocode (iData as Byte) 'writes the parameter of the Integer type M_OPCode CopyMemory M_opcode (m_opIndex), Idata, 2 m_opIndex = m_opIndex 2nd Sub

Private sub addbytetocode (bdata as Byte) 'writes the parameter of the Byte type M_opcode (m_opIndex) = bdata m_opIndex = m_opIndex 1END SUB

It is necessary to explain that Call calls, and the anti-compilation is called Call XXXXXXXX, and the corresponding ASM is E8 AAAAAAA. Note that the CALL instruction is a relative jump, the CPU is based on the current address when explaining the E8 AAAAAAAA, and the current address. This explains the following code: AddlongTocode LngProc - Varptr (m_opcode m_opIndex) - 4. Ok, I believe that readers who understand the content of the content is also easier to understand the above code. Note: An important feature is introduced from Visual Basic 5.0 in the Basic language: Addressof operator. This operator allows VB programmers to send their own function pointers directly. However, we can send a function pointer, but no one can send the function pointer to us. In fact, we can't even give us its own function pointer, because VB does not support call function pointers at all. (Good mouth!)

Third, the self-deletion of executable

(1) BAT file method assumes that it is to delete C: /MYDIR/selfdel.exe newly built a .bat file, write the following code in the file: RepeatDel "C: / mydir / selfdel.exe" if exist "Selfdel .Exe "goto review" C: / mydir "del" /delus.bat "The above code is a cyclic body, and the method of calling the deleted file in the loop has been deleted until the file is deleted. I don't explain the specific code. However, it is two shortcomings: First, the executable file is deleted, but there are more .bat files, or delete it, this is not in conjunction with our original intentions. Second, for an executable of the middle space, such as "Self DEL.EXE" cannot be deleted.

(2) Restart the deletion method

MovefileEx "C: / MyDir / SelfDel.exe", 0, MoveFile_DELAY_UNTIL_REBOOT This, the operating system registers the file you want to delete and remove it when restarting. This can be said to some of our desire. In fact, many commercial software requires "Please restart your computer to complete the installation process!", It is to remove the related files with the restart. Ok, the shortcomings of this method are also obvious, and the computer must be restarted to complete. It is also not what we want.

(3) The stack method is before giveing ​​the specific code, we talk about the relevant principles. In WIN32, the executor is ultimately to call CreateProcess. BOOL CreateProcess (LPCTSTR lpApplicationName, // pointer to name of executable module LPTSTR lpCommandLine, // pointer to command line string LPSECURITY_ATTRIBUTES lpProcessAttributes, // process security attributes LPSECURITY_ATTRIBUTES lpThreadAttributes, // thread security attributes BOOL bInheritHandles, // handle inheritance flag DWORD dwCreationFlags , // creation flags LPVOID lpEnvironment, // pointer to new environment block LPCTSTR lpCurrentDirectory, // pointer to current directory name lPSTARTUPINFO lpStartupInfo, // pointer to STARTUPINFOLPPROCESS_INFORMATION lpProcessInformation // pointer to PROCESS_INFORMATION); when you pass the executable lpApplicationName When the string of the file, the operating system will do the following things: 1. Find the executable file 2. Call the createFile () function Opens the file handle 3. Call CreateFileMapping with the open handle, map the code and data of the program to the address space of the process. I know the above steps, I want to come to you, I think that the delete file is in turn, 1. Call UnmapViewOffile Unfiles Map 2. Call Closehanle () Close the open file handle 3. DeleteFile () Delete file (the above step 1 and step 2 can be exchanged) sound perfect, isn't it? But actually can't complete our goals, why? When unmapViewoffile unloads the module of the executable file from the memory, the memory space where the module is located has also given the operating system, even if the EIP of the execution instruction or points to the original address, ready to execute the CloseHandle or deletefile, but that address has been operated The system is protected, "the skin is not deprecated, and the hair will be attached." It seems that we got a dead end. However, the operating system is not only to close the file handle, unlock the file memory image, and restore the stack, release reference to the DLL file, so we can put the code in the stack. 24 0 20 0 16 OFFSET BUF 12 Address of EXITPROCESS 8 Module 4 Address of DeletefileModule is the handle of the module, and BUF is the path to executable.

When the call Ret returns to unmapViewoffile, it is the place where the offset 0 in the stack is 0. When entering the unmapViewoffile process, the stack is seen in the stack to return the address deletefile and module. That is to say, return to the entrance of Deletefile after completion. Address. When returning to deletefile, see the address of EXITPROCESS, that is, return address. And parameter EAX, and EAX is the file name of EXE, which is buffer.buffer. By GetModuleFileName (Module, BUF, Benb (BUF)) Return. After executing deletefile, return to the EXITPROCESS function portal. And the parameter is 0 and the return address is 0.0 is an illegal address. If returned to address 0, it will be erroneous. And call EXITPROCESS should not return. Ca n'tforne, but we have a problem, VB does not support inline assembly, how can we construct such a stack and execute? We can apply for a readable write and execute memory, write our code in binary. Of course, the author introduces another method to you here. We can construct such a function and call public submyfun1 (Byval A1 As Long, Byval PTRTOBUF As Long, BYVAL EXITPRO As Long, Byval Module As Long, BYVAL DELFILE AS Long, Byval Unmapfile As Long, look At this time: 28 0 24 0 20 OFFSET BUF 16 Address of ExitProcess 12 Module 8 Address of Deletefile 4 Address of unmapViewoffile0 address of return address 89. Next, this return address is cleared. Remember STDCALL? "Subfincture is responsible for the stack", as long as another function is called, return it to the 4-byte stack space when returning. The complete code for: a form, a form button control Code: Dim Addr_ExitProcess As LongDim Addr_DeleteFile As LongDim Addr_UnmapViewOfFile As LongDim hm As LongPrivate Sub Form_Load () 'lret As Longhm = LoadLibrary (ByVal "Kernel32.dll")' Print Hex (hm)

Lret = getProcaddress (hm, byval "unmapViewoffile) addr_unmapviewoffile = LRET'PRINT HEX (Addr_UnmapViewoffile)

Lret = getProcaddress (hm, byval "deletefilea) addr_deletefile = LRET'PRINT HEX (addr_deletefile)

Lret = getProcaddress (hm, byval "exitprocess") addr_exitprocess = LRET'PRINT HEX (addr_exitprocess)

End Sub

PRIVATE SUB Command1_Click () DIM S AS STRING, LRET AS Longdim Hardcore As Longhm = getModuleHandle (VBnullstring)

IF HM = 0 Then Msgbox "Err Get Module"

'Print HEX (HM) S = String $ (MAX_PATH, 0) Lret = getModuleFileName (HM, S, lenb (s))

S = strconv (s, vbfromunicode) Hardcore = 4'Print S

DIM F1 AS Long, F2 As Long, F3 As Long, F4 As Long

Call dummyfun2

F1 = getFunaddress (addressof dummyfun1) f2 = getFunaddress (addressof dummyfun2)

Call MyCall2 (F1, F2) 'Print F1'Print F2

lret = CloseHandle (hardcore) 'If lret Then MsgBox "Close handle success"' DestroyWindow Me.hwndCall DummyFun1 (ByVal Addr_UnmapViewOfFile, ByVal Addr_DeleteFile, ByVal hm, ByVal Addr_ExitProcess, ByVal StrPtr (s), ByVal 0, ByVal 0)

End Sub

Module Code: Public Declare Function GetProcaddress LIB "Kernel32" (Byval LPPROCNAME AS STRING) AS Longpublic Declare Function DestroyWindow LIB "User32" (Byval Hwnd As Long) As long

Public Declare Function LoadLibrary Lib "kernel32" Alias ​​"LoadLibraryA" (ByVal lpLibFileName As String) As LongPublic Declare Function GetModuleHandle Lib "kernel32" Alias ​​"GetModuleHandleA" (ByVal lpModuleName As String) As LongPublic Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As LongPublic Declare Function GetModuleFileName Lib "kernel32" Alias ​​"GetModuleFileNameA" (ByVal hModule As Long, ByVal lpFileName As String, ByVal nSize As Long) As LongPublic Declare Function WriteProcessMemory Lib "kernel32" (ByVal hProcess As Long, lpBaseAddress As Any, LPBUFFER AS ANY, BYVAL NSIZE As Long, LPNUMBEROFBYTESWRITTEN AS Long AS Longpublic Declare Function GetCurrentProcess LIB "Kernel32" () AS Long

Public const Max_path = 260

Public Sub DummyFun1 (ByVal a1 As Long, ByVal a2 As Long, ByVal ptrToBuf As Long, ByVal ExitPro As Long, ByVal module As Long, ByVal delfile As Long, ByVal UnmapFile As Long) DummyFun1 = 1DummyFun1 = 1DummyFun1 = 1DummyFun1 = 1DummyFun1 = 1DummyFun1 = 1dummyfun1 = 1

End Sub

Public Sub DummyFun2 ()

Dummyfun2 = 1dummyfun2 = 1dummyfun2 = 1dummyfun2 = 1dummyfun2 = 1

End Sub

Public Function Getfunaddress (Byval Faddress As Long) As longgetfunaddress = faddressend function

Public Sub MyCall2 (lpFunOrigin As Long, lpFunReplace As Long) Dim bt As Byte, b As Byte, i As Integer, b2 As ByteDim ln As LongDim lret As Longbt = & HE8 'asm code for' call'b = & HC2 'asm code for 'ret 0040'i = & h4b2 = & hc3' asm code for 'RET' ln = lpfunreplace - lpfunorigin

Lret = WriteProcessMemory (getcurrentprocess, Byval Lpfunorigin, BT, 1, 0)

Lret = WriteProcessMemory (LPFunorigin 1), (Ln - 5), 4, 0) Lret = WriteProcessMemory (GetCurrentProcess, BYVAL (LPFunorigin 5), B2, 1, 0)

Lret = WriteProcessMemory (getCurrentProcess, Byval (LPFunReplace), B, 1, 0)

Lret = WriteProcessMemory (GetCurrentProcess, Byval (LpfunReplace 1), I, 2, 0)

End Sub

The code in memory in memory is called: Call Dummyfun2 retdummyfun2 in memory is: RET 0040 When executed in DummyFun1, the stack is performed: 32 0 28 0 24 Offset BUF 20 Address Of EXITPROCESS 16 MODULE 12 address of DeleteFile 8 address of UnmapViewOfFile4 address of return address0 address of return address in DummyFun1 executed next ret 0040, then returned to the DummyFun1 in the Eip, and stack address of return address is cleared, and then execute that our UNMAPVIEWOFFILE code. (Note: Be sure to generate an Exe file and then execute, do not perform the above code in the compilation environment of the VB, otherwise, the consequences are at your own risk, the task is completed, is it a sense of accomplishment? But this can only be executed under Windows 2000, and it will not work in 98 / XP. Under XP, due to Handle (4) no longer corresponds to an exe, it is not successful. Under 98, just replace unmapViewoffiles to FREELIBRARY. (4) Remote thread This is the most complex method known to know, involving process, thread, code relocation, etc., VB is more complicated, powerful, and interested readers can write itself.

转载请注明原文地址:https://www.9cbs.com/read-118271.html

New Post(0)