The following instructions are a guide to attacking the licensing protections employed by VirtualHere USB server. The methodology is different in that it does not coerce control flow as much but instead replaces a single instruction by its counterpart in order to dismantle all licensing checks.
Limitation of the unregistered software include:
etc…
The procedure is a two-part attack:
VirtualHere USB seems to rely on some inline Base64 encoded data to mark the software as unlicensed when running the program in trial mode. In case the Base64 data is modified, then VirtualHere USB will announce that the license is invalid. This behaviour can be observed in sub_422c90
in the decompiled source:
0000000000422ce8 mov edx, 0x1 ; argument #3 for method sub_405340, XREF=sub_422c90+38 0000000000422ced mov esi, 0x5dd1f8 ; "unlicensed,1,MCACDkn0jww6R5WOIjFqU/apAg4Um+mDkU2TBcC7fA1FrA==", argument #2 for method sub_405340 0000000000422cf2 mov edi, 0x5d7fc9 ; "License", argument #1 for method sub_405340 0000000000422cf7 call sub_405340 0000000000422cfc mov rbx, rax 0000000000422cff mov rdi, rax ; argument #1 for method sub_422af0 0000000000422d02 call sub_422af0 0000000000422d07 mov rdi, rbx 0000000000422d0a call sub_420150 0000000000422d0f test rax, rax 0000000000422d12 mov qword [ds:0x892bf8], rax 0000000000422d19 je 0x422d98
The code calls the soubroutine sub_405340
with function parameters: License
, unlicensed,1,MCACDkn0jww6R5WOIjFqU/apAg4Um+mDkU2TBcC7fA1FrA==
and 1
. In case the second parameter (unlicensed,1,MCACDkn0jww6R5WOIjFqU/apAg4Um+mDkU2TBcC7fA1FrA==
) passed to sub_405340
is tampered with, then VirtualHere USB will display on startup:
LOG_ERR Invalid License LOG_INFO Server licensed to=unlicensed max_devices=1
The latter behaviour can be traced to subroutine sub_420150
of the decompiled code that performs various licensing checks resulting (most likely, if unfavourable) to a jump into the segment:
; ... 0000000000420338 mov rcx, qword [ds:0x643d68] ; argument #4 for method sub_5cb6dd, XREF=sub_420150+113, sub_420150+145, sub_420150+177, sub_420150+206, sub_420150+660, sub_420150+702, sub_420150+785, sub_420150+801, sub_420150+1091 000000000042033f mov edx, 0x10 ; argument #3 for method sub_5cb6dd 0000000000420344 mov esi, 0x1 ; argument #2 for method sub_5cb6dd 0000000000420349 mov edi, 0x5dd287 ; "Invalid License\\n", argument #1 for method sub_5cb6dd 000000000042034e call sub_5cb6dd 0000000000420353 mov esi, 0x5d7fc1 0000000000420358 mov edi, 0x3 000000000042035d xor eax, eax 000000000042035f call sub_414d90 0000000000420364 mov esi, 0x34 ; argument #2 for method sub_5c5380 0000000000420369 mov edi, 0x1 ; argument #1 for method sub_5c5380 000000000042036e call sub_5c5380 0000000000420373 mov rbx, rax 0000000000420376 movabs rax, 0x736e6563696c6e75 0000000000420380 mov qword [ds:rbx], rax 0000000000420383 mov eax, 0x6465 0000000000420388 mov byte [ds:rbx+0xa], 0x0 000000000042038c mov word [ds:rbx+0x8], ax 0000000000420390 mov dword [ds:rbx+0x28], 0x1 0000000000420397 mov byte [ds:rbx+0x30], 0x1 ; ...
that is responsible for marking the license as invalid and hence enforcing all trial limitations. However, if the code segment starting at 0x420338
, then VirtualHere USB has no way to determine whether the license is invalid or not. Following the latter reasoning, a jump is injected at the very start of the code segment 0x420338
and up to 0x42039b
, after the code segment.
0000000000420338 jmp 0x42039b ; XREF=sub_420150+113, sub_420150+145, sub_420150+177, sub_420150+206, sub_420150+660, sub_420150+702, sub_420150+785, sub_420150+801, sub_420150+1091 000000000042033d nop 000000000042033e nop 000000000042033f mov edx, 0x10 ; argument #3 for method sub_5cb6dd 0000000000420344 mov esi, 0x1 ; argument #2 for method sub_5cb6dd 0000000000420349 mov edi, 0x5dd287 ; "Invalid License\\n", argument #1 for method sub_5cb6dd 000000000042034e call sub_5cb6dd ; ... 000000000042039b mov rdi, rbp ; argument #1 for method sub_5c5a10, XREF=sub_420150+488, sub_420150+875 000000000042039e call sub_5c5a10 00000000004203a3 add rsp, 0x598 00000000004203aa mov rax, rbx 00000000004203ad pop rbx 00000000004203ae pop rbp 00000000004203af pop r12 00000000004203b1 pop r13 00000000004203b3 pop r14 00000000004203b5 pop r15 00000000004203b7 ret
Now VirtualHere USB cannot set itself as using an invalid license however, the code is not reached unless the license is indeed invalid such that the unlicensed hash unlicensed,1,MCACDkn0jww6R5WOIjFqU/apAg4Um+mDkU2TBcC7fA1FrA==
has to be destroyed to trigger the now modified invalid license code. To do so, the string is contained within the program starting with address 0x5dd1f8
:
00000000005dd1f8 db "unlicensed,1,MCACDkn0jww6R5WOIjFqU/apAg4Um+mDkU2TBcC7fA1FrA==", 0 ; XREF=sub_422c90+93
and it is sufficient to just modify a single byte to trigger the invalid license code.
When running VirtualHere USB, the program will now display:
Server licensed to= max_devices=1919247151
which is not vary pretty and just begs for a vanity fix.
The string Server licensed to=%s %s
can be found referenced in the subroutine sub_422930
:
sub_422930: 0000000000422930 push rbx ; XREF=sub_422c90+197 0000000000422931 sub rsp, 0x20 0000000000422935 mov rdx, qword [ds:0x892bf8] 000000000042293c mov eax, dword [ds:rdx+0x28] 000000000042293f test eax, eax 0000000000422941 jne 0x422980 0000000000422943 movdqa xmm0, xmmword [ds:0x5dd570] ; "max_devices=unliDeregistered interface %s\\n" 000000000042294b mov eax, 0x64 0000000000422950 mov rbx, rsp 0000000000422953 mov dword [ss:rsp+var_18], 0x6574696d 000000000042295b mov word [ss:rsp+var_14], ax 0000000000422960 movaps xmmword [ss:rsp+var_28], xmm0 0000000000422964 mov rcx, rbx ; XREF=sub_422930+107 0000000000422967 mov esi, 0x5dd4e3 ; "Server licensed to=%s %s" 000000000042296c mov edi, 0x6 0000000000422971 xor eax, eax 0000000000422973 call sub_414d90 0000000000422978 add rsp, 0x20 000000000042297c pop rbx 000000000042297d ret 000000000042297e nop 0000000000422980 mov rbx, rsp ; XREF=sub_422930+17 0000000000422983 mov edx, eax 0000000000422985 mov esi, 0x5dd4d4 ; "max_devices=%d" 000000000042298a mov rdi, rbx 000000000042298d xor eax, eax 000000000042298f call sub_5cbda2 0000000000422994 mov rdx, qword [ds:0x892bf8] 000000000042299b jmp 0x422964
the jne
at 0x422941
has already been taken care of in the previous section such that no modification is necessary. On the other hand, the referenced string Server licensed to=%s %s
can be found inline at address 0x5dd4e3
:
00000000005dd4e3 db "Server licensed to=%s %s", 0 ; XREF=sub_422930+55
and can be replaced with any other 24 characters - note that this will overwrite the parameters %s
that interpolates some variables at runtime using a printf
formatting function but that does not matter because by replacing the string the parameters will just be ignored.
The string Server licensed to=%s %s
at 0x5dd4e3
reads, in hex:
53 65 72 76 65 72 20 6c 69 63 65 6e 73 65 64 20 74 6f 3d 25 73 20 25 73
and that can be replaced by, say:
57 69 7a 61 72 64 72 79 20 61 6e 64 20 53 74 65 61 6d 77 6f 72 6b 73 00
thereby making the program display:
LOG_INFO Wizardry and Steamworks
instead of:
LOG_INFO Server licensed to= max_devices=1919247151