Timer Patch Solution

Tạo vào: 18 tháng 1, 2025

Trả lời bằng OpenAI 01 bởi OpenAI01

Câu hỏi

Solve task with my assembly, how to patch it? easy way needed.

My_assembly : {
push edx
.text:0040B03E lea ecx, [ebp+var_28C]
.text:0040B044 push eax
.text:0040B045 lea edx, [ebp+var_27C]
.text:0040B04B push ecx
.text:0040B04C lea eax, [ebp+var_26C]
.text:0040B052 push edx
.text:0040B053 lea ecx, [ebp+var_25C]
.text:0040B059 push eax
.text:0040B05A lea edx, [ebp+var_24C]
.text:0040B060 push ecx
.text:0040B061 lea eax, [ebp+var_23C]
.text:0040B067 push edx
.text:0040B068 lea ecx, [ebp+var_22C]
.text:0040B06E push eax
.text:0040B06F lea edx, [ebp+var_21C]
.text:0040B075 push ecx
.text:0040B076 lea eax, [ebp+var_20C]
.text:0040B07C push edx
.text:0040B07D push eax
.text:0040B07E push 2Fh ; '/'
.text:0040B080 call ds:__vbaFreeVarList
.text:0040B086 mov eax, [ebp+arg_0]
.text:0040B089 add esp, 0C0h
.text:0040B08F mov ecx, [eax]
.text:0040B091 push eax
.text:0040B092 call dword ptr [ecx+708h]
.text:0040B098 mov eax, [ebp+arg_0]
.text:0040B09B push eax
.text:0040B09C mov edx, [eax]
.text:0040B09E call dword ptr [edx+708h]
.text:0040B0A4 mov eax, [ebp+arg_0]
.text:0040B0A7 push eax
.text:0040B0A8 mov ecx, [eax]
.text:0040B0AA call dword ptr [ecx+708h]
.text:0040B0B0 mov eax, [ebp+arg_0]
.text:0040B0B3 lea ecx, [ebp+var_1C]
.text:0040B0B6 push ecx
.text:0040B0B7 push eax
.text:0040B0B8 mov edx, [eax]
.text:0040B0BA call dword ptr [edx+50h]
.text:0040B0BD cmp eax, ebx
.text:0040B0BF fnclex
.text:0040B0C1 jge short loc_40B0D5
.text:0040B0C3 mov edx, [ebp+arg_0]
.text:0040B0C6 push 50h ; 'P'
.text:0040B0C8 push offset dword_40201C
.text:0040B0CD push edx
.text:0040B0CE push eax
.text:0040B0CF call ds:__vbaHresultCheckObj
.text:0040B0D5
.text:0040B0D5 loc_40B0D5: ; CODE XREF: sub_40AB60+561↑j
.text:0040B0D5 mov eax, [ebp+var_1C]
.text:0040B0D8 push 44h ; 'D'
.text:0040B0DA mov [ebp+var_2B4], eax
.text:0040B0E0 lea eax, [ebp+var_2C]
.text:0040B0E3 push eax
.text:0040B0E4 mov [ebp+var_1C], ebx
.text:0040B0E7 mov [ebp+var_2BC], 8008h
.text:0040B0F1 call esi ; rtcVarBstrFromAnsi
.text:0040B0F3 lea ecx, [ebp+var_3C]
.text:0040B0F6 push 65h ; 'e'
.text:0040B0F8 push ecx
.text:0040B0F9 call esi ; rtcVarBstrFromAnsi
.text:0040B0FB lea edx, [ebp+var_5C]
.text:0040B0FE push 66h ; 'f'
.text:0040B100 push edx
.text:0040B101 call esi ; rtcVarBstrFromAnsi
.text:0040B103 lea eax, [ebp+var_7C]
.text:0040B106 push 43h ; 'C'
.text:0040B108 push eax
.text:0040B109 call esi ; rtcVarBstrFromAnsi
.text:0040B10B lea ecx, [ebp+var_9C]
.text:0040B111 push 61h ; 'a'
.text:0040B113 push ecx
.text:0040B114 call esi ; rtcVarBstrFromAnsi
.text:0040B116 lea edx, [ebp+var_BC]
.text:0040B11C push 6Dh ; 'm'
.text:0040B11E push edx
.text:0040B11F call esi ; rtcVarBstrFromAnsi
.text:0040B121 lea eax, [ebp+var_DC]
.text:0040B127 push 70h ; 'p'
.text:0040B129 push eax
.text:0040B12A call esi ; rtcVarBstrFromAnsi
.text:0040B12C lea ecx, [ebp+var_FC]
.text:0040B132 push 20h ; ' '
.text:0040B134 push ecx
.text:0040B135 call esi ; rtcVarBstrFromAnsi
.text:0040B137 lea edx, [ebp+var_11C]
.text:0040B13D push 43h ; 'C'
.text:0040B13F push edx
.text:0040B140 call esi ; rtcVarBstrFromAnsi
.text:0040B142 lea eax, [ebp+var_13C]
.text:0040B148 push 54h ; 'T'
.text:0040B14A push eax
.text:0040B14B call esi ; rtcVarBstrFromAnsi
.text:0040B14D lea ecx, [ebp+var_15C]
.text:0040B153 push 46h ; 'F'
.text:0040B155 push ecx
.text:0040B156 call esi ; rtcVarBstrFromAnsi
.text:0040B158 lea edx, [ebp+var_17C]
.text:0040B15E push 20h ; ' '
.text:0040B160 push edx
.text:0040B161 call esi ; rtcVarBstrFromAnsi
.text:0040B163 lea eax, [ebp+var_19C]
.text:0040B169 push 43h ; 'C'
.text:0040B16B push eax
.text:0040B16C call esi ; rtcVarBstrFromAnsi
.text:0040B16E lea ecx, [ebp+var_1BC]
.text:0040B174 push 72h ; 'r'
.text:0040B176 push ecx
.text:0040B177 call esi ; rtcVarBstrFromAnsi
.text:0040B179 lea edx, [ebp+var_1DC]
.text:0040B17F push 61h ; 'a'
.text:0040B181 push edx
}

Solution : {
We start by loading program in VB Decompiler. We can extract some interesting
information from there:

1. Begin Timer Timer1 ; Declare a timer with name Timer1
Interval = 3000 ; trigger every 3 secs (3000 = 0xBB8)
Left = 2760
Top = 720
End
2. Private Sub Timer1_Timer() '40AB60 ; timer handler
3. Private Sub Command1_Click() '402F90 ; button click handler
4. Private Sub Form_Load() '408100 ; handler for OnLoad event
5. 'VA: 4021A0
Private Declare Sub IsDebuggerPresent Lib "kernel32"()
// ----------------------------------------------------------------------------------- //
Now, open IDA (or Olly, we won't use any special feature of IDA) and try to remove
debugging protection. Inside Form_Load() we have:

.text:00408B6F push ecx ; arg4: v_4dc
.text:00408B70 lea ecx, [ebp-1Ch]
.text:00408B73 push edx ; arg3: "Ollydbg"
.text:00408B74 push ecx ; arg2: v_1c
.text:00408B75 push ebx ; arg1: 0040E3E8
.text:00408B76 call dword ptr [eax+704h] ; Proc_0_5_405BA0
.text:00408B7C cmp word ptr [ebp-4DCh], 0FFFFh
.text:00408B84 jnz short loc_408BB1 ; if v_4dc != -1 skip bad code

Function Proc_0_5_405BA0 is called with argument "Ollydbg". If returns -1, then program
terminates. Proc_0_5_405BA0 is called many times with the following arguments:
1.Ollydbg
2.PEiD
3.Windows
4.IDA
5.Hex
6.CPU

Proc_0_5_405BA0 may looks for window names and return -1 when detects a window with
such a name. I am using IDA and function returns -1 when IDA argument is called. A
fast analysis of this function shown that is searching all windows for window_text
that contains the specified string. All we have to do is to set a breakpoint at:
.text:00408B84 jnz short loc_408BB1 ; if you use Olly
.text:0040977A jz loc_4090F6 ; if you use IDA

and toggle ZF flag to cancel branch.
// ----------------------------------------------------------------------------------- //
Then, form appears to screen, but it closes again. We can blame timer handler for
this. When Proc_0_6_405D60 is called, then form closes:
.text:0040B092 call dword ptr [ecx+708h] ; Proc_0_6_405D60

Inside Proc_0_6_405D60, we have the same protection as in Form_Load(). We can bypass
it as before, but after 3 seconds, we have to bypass it again, and again... This is
very annoying. However, there are (at least) 2 solutions for this:
1. Patch jz command with jnz command. (easy)
2. Tamper timer's interval. (difficult)

The first solution is quite simple, so I'll show the second. Let's get into Visual
Basic Internals. Set a breakpoint at EntryPoint:
.text:004014C4 public start
.text:004014C4 start:
.text:004014C4 push offset dword_401880 ; RT_MainStruct
.text:004014C9 call ThunRTMain

This is the main struct of the program, and contains lots of information about program:
00401880: 56 42 35 21 --> VB5! ; signature
00401884: F0 1F 2A 00 --> dd 0x002a1ff0
........
004018cc: 30 18 40 00 --> offset 0x00401830 -> DialogsStruct
........

Follow DialogsStruct:
00401830: 50 00 00 00 --> sizeof struct
00401834: 7C 6C A5 22 -->
........
00401878: 14 15 40 00 --> offset 0x00401514 -> MainDialog
........

Follow MainDialog. This struct contains all information about form and objects of
the program. It's easy to determine the declaration of Timer object, because we
know it's name (Timer1):
00401714 FF 01 1F 00 00 00 01 06 00 54 69 6D 65 72 31 00  ........Timer1.
00401724 0B 03 B8 0B 00 00 07 C8 0A 00 00 08 D0 02 00 00 .._....L...._...

The 2 bytes at 00401726 (0B B0) is the time interval (0x0BB0 = 3000). One solution
is to set the interval to very big value (0x7BB8 = 31 sec). But the problem is not
solved. You can also find where the Enabled property is located and set it to false.
But we'll implement something different: We'll set the interval at an illegal value
(0x0000). Thus timer handler will fail, and will never execute.
}

Suy nghĩ

Analyzing assembly code

I’m examining assembly code from a VB6 program, which employs debugging detection methods like comparing registers and calling functions. Efforts to detect a debugger include examining specific calls and conditional jumps.

Considering patch options

OK, let me see. The user is pondering on skip-calling or modifying a function. Disabling the Timer by setting its interval to zero is another viable approach.

Tweaking the flow

It's clear that changing the conditional jump from "jge" to "jmp" bypasses the call to "ds:__vbaHresultCheckObj," which effectively avoids executing the function.

Tweaking offsets

The user could be suggesting a quick patch by altering the "jge" to "jmp" at offset 0x40B0C1 or adjusting the Timer's interval to zero at offset 0x1726 for simplicity.

Opting for quick tweaks

I’m gathering info on modifying the jump at offset 0x40B0C1 or tweaking the Timer's interval at offset 0x1726. Both methods are swift approaches for making the required changes.

Thought about assembly patching methods for 13 seconds

Trả lời

Below is a concise, practical explanation of how to disable the troublesome timer (or the check) with a simple patch, so that the form does not close repeatedly every few seconds. I’ll outline two common methods:


1) Patch the jump in the Timer code (skip the bad branch)

Looking at the snippet around:

.text:0040B0BD  cmp     eax, ebx
.text:0040B0BF  fnclex
.text:0040B0C1  jge     short loc_40B0D5
.text:0040B0C3  mov     edx, [ebp+arg_0]
.text:0040B0C6  push    50h ; 'P'
.text:0040B0C8  push    offset dword_40201C
.text:0040B0CD  push    edx
.text:0040B0CE  push    eax
.text:0040B0CF  call    ds:__vbaHresultCheckObj
.text:0040B0D5  ; -----------------------------------------------------------------
loc_40B0D5:
  • The cmp eax, ebx/jge short loc_40B0D5 sequence checks some condition that, if failing, calls __vbaHresultCheckObj (which in many VB6 protections can terminate or glitch the program).

  • If you want to always skip that termination call, you can simply replace jge short loc_40B0D5 (opcodes typically 7D 12 in hex) with an unconditional jump (EB 12).

  • Concretely, if you are using a hex editor, search for the bytes 7D 12 at that address and change the 7D to EB. In assembly, it changes from:

    jge  short loc_40B0D5
    

    to

    jmp  short loc_40B0D5
    

    This way, it never executes the block at 0x40B0C3 and never calls __vbaHresultCheckObj.

This is often the quickest fix for these repeated calls that forcibly close the form.


2) Disable (or cripple) the Timer by changing its Interval

As you found, the form uses a standard VB Timer object (Timer1) with an Interval property of 3000ms (0x0BB8). When that timer expires, it calls into the same anti-debug routine. Disabling (or sabotaging) the timer means that code never fires in the background.

From your research, you see in the VB form structure (often in the data area of the compiled VB program) something like:

00401714  ... "Timer1"
00401724  0B 03 B8 0B 00 00 07 C8 ...
              ^^^^
              Timer Interval

Depending on the exact layout, you’ll see B8 0B which is 0x0BB8 in little-endian (3000 decimal).

  1. Set the Interval to 0
    Replace B8 0B with 00 00. This yields an Interval of 0, which VB considers invalid, and effectively the timer never fires.
  2. Set the Interval to a huge value
    If you don’t want to completely break the timer, you could set it to something like FF 7F (0x7FFF ~ 32767 ms), or any large number. But usually 0 is enough to kill it outright.

Either approach stops the repeated calls.


Which is “easiest”?

  • Changing the jump (Method #1) is simplest if you are comfortable with disassembly and know exactly where that short jump is. You just turn jgejmp, and done.
  • Changing the Timer Interval (Method #2) is often simpler if you have a direct offset in the file for Timer1.Interval. You just open a hex editor at the correct offset, change two bytes to 00 00, and you’re finished.

Both approaches work. You only need to apply one of them to keep the form from closing itself every few seconds.


Summary

  1. Open the EXE (or the compiled binary) in a hex editor or disassembler.
  2. Option A: Locate the code around cmp eax, ebx / jge short loc_40B0D5, change jge into an unconditional jmp (hex 7DEB).
  3. Option B: Locate the Timer1 structure and set its Interval from 0x0BB8 (3000) to 0x0000. This disables the timer.

Either patch should stop the timer-based anti-debug checks from closing the form.

Chia sẻ Q&A này