Paranoic protection (expression by Marigold) of Radmin
Target : Remote administrator viewer v1.1.0.1 from http://www.mtu-net.ru/radmin/
tools: sice
idaw
custom program to dump memory locations(procdump of no use here)
patch maker.
let us begin investigating.
first time after starting the program we can see a nag screen with
three buttons "ok","register",and "cancel",let us move our time a year ahead.
and press "ok" button.Ups-messagebox with message:
'Evalution period is expired,enter the registration code to continue using the program.'
so
>>bpx messageboxa and try again
pop up in sice with address c797a8 (after F11)
ok, let us disassemble the program. at first in wdasm, and what we see? nothing,
no such addresses,and within the offset from base there is no such instructions,
and it means - we have packed(or crypted ) target.
let us start procdump to view what module is in the location - :( - NONE
so going to sice
>>addr radmin
>>d c97a8
and let us determine the bounds of memory occupied by the strange code
after some
>>d c90000
>>d c80000
...
>>d cf0000
>>d cd0000
ve can found that a module boundz with "MZ"...."PE" signatures at
c70000
and un allocated memory at
cf0000
Ok.here we are ? let us dump the memory.
as i sayed procdump is of no use in the case(and i think in most other(opinion
from my expirience -may be i am just not able to undestand it)) and i have quickly wrote
a small program , with CreateProcess and ReadProcessMemory and dumped the memory to disk
after this i have loaded it into ida(great tool) as binary file,setting the load offset to
c70000 and do not create segments to on
then in ida i have created a 32 bit segment , named code and started my work.
first, let's
>>G c71000
and press c
so here is a code -it is clear
some time after all i have pressed here and there some keys, defining what is code , data and offsets
and, finally applyed a flirt signatures vcrtf32 3/4/5 and mfc 32 bit
then go to our messageboxa call at c97a8
and see
such a code
LISTING 1.
code:00C7974C test eax, eax
code:00C7974E*
code:00C7974E*jmpok: ; DATA XREF: code:00C7B553vw
code:00C7974E* jnz short close_to_fin
code:00C79750 push 40h ; '@'
code:00C79752 push offset aInformation ; "Information"
code:00C79757 push offset aEvalutionPerio ; "Evalution period is expired,\nenter the "...
code:00C7975C mov ecx, [ebp+arg_0]
code:00C7975F push ecx
code:00C79760 call dword ptr ds:0C9721Ch
code:00C79766 xor eax, eax
code:00C79768
code:00C79768 newend:
code:00C79768 jmp return
code:00C7976D ; ---------------------------------------------------------------------------
code:00C7976D
code:00C7976D close_to_fin: ; CODE XREF: nagproc+85E^j
code:00C7976D cmp [ebp+var_1B0], 14h
code:00C79774* jbe short ok_proseed
code:00C79776 mov edx, 1Eh
code:00C7977B sub edx, [ebp+var_1B0]
code:00C79781 push edx
code:00C79782 push offset aThisProgramIsS ; "%This program is shareware.\nYour 30-day"...
code:00C79787 lea eax, [ebp+days_left]
code:00C7978D push eax
code:00C7978E call _sprintf
code:00C79793 add esp, 0Ch
code:00C79796 push 40h ; '@'
code:00C79798 push offset aInformation ; "Information"
code:00C7979D lea ecx, [ebp+days_left]
code:00C797A3 push ecx
code:00C797A4 mov edx, [ebp+arg_0]
code:00C797A7 push edx
code:00C797A8 call dword ptr ds:0C9721Ch
code:00C797AE
code:00C797AE ok_proseed: ; CODE XREF: nagproc+84F^j
code:00C797AE ; nagproc+884^j
EOL listing
so going to 0c9721c we can see a table of addresses
...
code:00C97210 dd 77E721DFh
code:00C97214 dd 77E72575h ; DATA XREF: nagproc+730^r
code:00C97214 ; nagproc+8E4^r
code:00C97214 ; nagproc+91E^r
code:00C97214 ; nagproc+945^r
code:00C97214 ; main_prg+19A^r
code:00C97214 ; main_prg+29F^r
code:00C97218 dd 77E71C61h ; DATA XREF: nagproc+D79^r
code:00C9721C dd 77E8A590h ; DATA XREF: nagproc+495^r
code:00C9721C ; nagproc+5D7^r
code:00C9721C ; nagproc+662^r
code:00C9721C ; nagproc+702^r
code:00C9721C ; nagproc+870^r
code:00C9721C ; nagproc+8B8^r
code:00C9721C ; main_prg+2BF^r
code:00C9721C ; code:00C7B677^r
code:00C97220 dd 77E71C53h ; DATA XREF: nagproc+9AA^r
code:00C97224 dd 77E72567h ; DATA XREF: nagproc+3FE^r
code:00C97228 dd 77E76D8Eh
code:00C9722C dd 77E74841h
code:00C97230 dd 77EB0C3Eh
code:00C97234 dd 77E73F14h
code:00C97238 dd 77E72441h
code:00C9723C dd 77E75BF5h
...
it is clear that it is a table of imported functions, but it seens tobe that strings with names of the functions
and modules are absent(or erased).
here is the point to start learning ida C scripting.
after some learning and RE of availiable IDCs i have wrote a script
LISTING 2.
#include
/*
**************************************************************************************
the script is intended to recover imported functions names from dumped files with erased
fuctions names i.e. only import table with function addreses present
(c) staier from http://staier.cjb.net
All rights reserved
you can use & modyfy it freely until this comment is erased
format of *.exp file:
----------------------
gdi32.dll
Number of Exported Functions = 0401 (decimal)
Addr:77EE9BB6 Ord: 1 (0001h) Name: AbortDoc
Addr:77EEA5A1 Ord: 2 (0002h) Name: AbortPath
Addr:77EDB23F Ord: 3 (0003h) Name: AddFontResourceA
Addr:77EE69BA Ord: 4 (0004h) Name: AddFontResourceTracking
Addr:77EE6C06 Ord: 5 (0005h) Name: AddFontResourceW
...
Addr:77EE80AC Ord: 401 (0191h) Name: gdiPlaySpoolStream
---------------
taken from wdasm .alf file
original file http://staier.cjb.net/fname.zip contains kernel32.exp, advapi32.exp,gdi32.exp
user32.exp
****************************************************************************************
*/
static getfuncnames()
{
auto c,c2,c3;
auto hndl,start;
hndl=fopen(AskFile(0,"*.exp","enter export file name"),"rt");
Message("opening exports file ");
if (!hndl) {Message("opening exports file failed ");
Exit(1);
};
start=AskAddr( BADADDR,"enter start address");
if (start == BADADDR)
{Message(" can not obtain an address");
Exit(1);
};
c=readstr(hndl);
Message("module export:%s ",c);
c=readstr(hndl);
Message("starting analyse from :%x \n",start);
Message(c);
while ((c=readstr(hndl))!=-1)
{
c2=start;
Message(c);
Message("address:%s,name:%s \n",substr(c,6,14),substr(c,38,strlen(c)));
while (Dword(c2)!=0) //end of table for a given imported module
{// Message("address:%s,indisasm:%x \n",substr(c,6,14),Dword (c2)); -for debugging
if (Dword (c2)==xtol(substr(c,6,14)))
{MakeName(c2,substr(c,38,strlen(c)-1));
MakeComm(c2,"exported function");
Message("found function");
break;
}
else c2=c2+4;
};
};
fclose(hndl);
}
static main()
{
getfuncnames();
}
EOL 2.
so starting the script here and there we'v got:
code:00C97210 BeginPaint dd 77E721DFh ; exported function
code:00C97214 SendMessageA dd 77E72575h ; DATA XREF: nagproc+730^r
code:00C97214 ; nagproc+8E4^r
code:00C97214 ; nagproc+91E^r
code:00C97214 ; nagproc+945^r
code:00C97214 ; main_prg+19A^r
code:00C97214 ; main_prg+29F^r
code:00C97214 ; exported function
code:00C97218 ReleaseDC dd 77E71C61h ; DATA XREF: nagproc+D79^r
code:00C97218 ; exported function
code:00C9721C MessageBoxA dd 77E8A590h ; DATA XREF: nagproc+495^r
code:00C9721C ; nagproc+5D7^r
code:00C9721C ; nagproc+662^r
code:00C9721C ; nagproc+702^r
code:00C9721C ; nagproc+870^r
code:00C9721C ; nagproc+8B8^r
code:00C9721C ; main_prg+2BF^r
code:00C9721C ; code:00C7B677^r
code:00C9721C ; exported function
code:00C97220 GetDC dd 77E71C53h ; DATA XREF: nagproc+9AA^r
code:00C97220 ; exported function
code:00C97224 InvalidateRect dd 77E72567h ; DATA XREF: nagproc+3FE^r
code:00C97224 ; exported function
code:00C97228 SetScrollPos dd 77E76D8Eh ; exported function
code:00C9722C SetScrollRange dd 77E74841h ; exported function
code:00C97230 ShowScrollBar dd 77EB0C3Eh ; exported function
code:00C97234 SetWindowPos dd 77E73F14h ; exported function
code:00C97238 GetWindowRect dd 77E72441h ; exported function
code:00C9723C SetWindowLongA dd 77E75BF5h ; exported function
and our code fragment is looking no like this
LISTING 3.
code:00C7974C test eax, eax
code:00C7974E*
code:00C7974E*jmpok: ; DATA XREF: code:00C7B553vw
code:00C7974E* jnz short close_to_fin
code:00C79750 push 40h ; '@'
code:00C79752 push offset aInformation ; "Information"
code:00C79757 push offset aEvalutionPerio ; "Evalution period is expired,\nenter the "...
code:00C7975C mov ecx, [ebp+arg_0]
code:00C7975F push ecx
code:00C79760 call ds:MessageBoxA
code:00C79766 xor eax, eax
code:00C79768
code:00C79768 newend:
code:00C79768 jmp return
code:00C7976D ; ---------------------------------------------------------------------------
code:00C7976D
code:00C7976D close_to_fin: ; CODE XREF: nagproc+85E^j
code:00C7976D cmp [ebp+var_1B0], 14h
code:00C79774* jbe short ok_proseed
code:00C79776 mov edx, 1Eh
code:00C7977B sub edx, [ebp+var_1B0]
code:00C79781 push edx
code:00C79782 push offset aThisProgramIsS ; "%This program is shareware.\nYour 30-day"...
code:00C79787 lea eax, [ebp+days_left]
code:00C7978D push eax
code:00C7978E call _sprintf
code:00C79793 add esp, 0Ch
code:00C79796 push 40h ; '@'
code:00C79798 push offset aInformation ; "Information"
code:00C7979D lea ecx, [ebp+days_left]
code:00C797A3 push ecx
code:00C797A4 mov edx, [ebp+arg_0]
code:00C797A7 push edx
code:00C797A8 call ds:MessageBoxA
code:00C797AE
code:00C797AE ok_proseed: ; CODE XREF: nagproc+84F^j
code:00C797AE ; nagproc+884^j
EOL 3.
here we are
we can see that passing the jumps at
code:00C7974E and
code:00C79774*
we can pass the expiration routine right way
let us go to sice
and
>>addr radmin
>>bpx 00C7974E
and let us gentle cpass the gumps changing the flag register
ok, me have passed , but after trying to connect to radmin server we are crashed
what is the hell?
the eanswer is that there is a control sum check on the code of verification routine and we can be aware of the
fact by setting
bpm 00C7974E r
it will be a pup up of sice in address 00009c...
(another hidden module)
the point is that sice bpx is an int 3 instruction embedded into the code
so let us clear the bpx after passing the routine
this time all works fine.
now it is time to write path for the program.
we must perform 3 steps:
1.wait for code will be unpacked
2.change jump at 00C79760 to our code
3.restore virginity and jump to 00C797AE
i have used my favourite method of installing new thread into the code.
me must first to chanje entrypoint and virtual size of .code cection of the program 200h would be fine
and in hex editor fill the place of our code with nops and et the end of it jmp to old entrypoin.
(this is becouse of ida behavour , that translate unused bytes to ORG -org 400 in the case).
and let us code our prog directly in ida.
LISTING 4(from produced ASM file)
start: ; "KERNEL32.dll"
push offset aKernel32_dll
call cs:GetModuleHandleA
push eax
push 44h
push eax
call cs:GetProcAddress
mov CreateThread, eax
pop eax
push eax
push 6Dh
push eax
call cs:GetProcAddress
mov ExitThread, eax
pop eax
push 243h
push eax
call cs:GetProcAddress
mov Sleep, eax
push offset return
push 0
push 0
push offset thr_fn
push 0
push 0
call cs:CreateThread
jmp entry ; _WinMainCRTStartup
; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
db 1 ;
db 0 ;
; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
thr_fn: ; DATA XREF: .text:01409D99o
push 5DCh
call cs:Sleep
mov eax, base_of_1_9c000;address of dword, containing address of module ? wich unpacks module at c90000
loc_0_1409DC1:
add eax, 2FA18h
mov ebx, [eax]
add ebx, 272ECh
loc_0_1409DCE: ; CODE XREF: .text:01409DD4j
cmp dword ptr [ebx], 0
jz short loc_0_1409DCE
sub ebx, 272ECh
add ebx, 974Eh
mov byte ptr [ebx], 0E9h
mov eax, 7906ADh
sub eax, ebx
add eax, 0C7974Eh
mov [ebx+1], eax
push 0
call ss:ExitThread
retn 4
; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
mov eax, base_of_1_9c000 ;jump from target code here
add eax, 2FA18h
mov eax, [eax]
add eax, 974Eh
mov byte ptr [eax], 75h ;restore
mov dword ptr [eax+1], 68406A1Dh ;virginity
add eax, 60h
push eax
xor eax, eax
retn ;jump back to target code
; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
xor eax, eax
retn
; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
...
EOL 4.
after writing,produce the DIFF file right from the Ida IDE and make patch. that is all.
some notes
1.i do not bother to show you right addreses,as we are reversers we can find it easely
they can be found by setting "bpm ... w" to start addresses of hidden modules.
note that there is other modules.(dump them and disassemble, using described teckniques)
by the way , i have spent about a week to handle the tasks(yeah-i'm not a reverser GOD).
2. the patched program works only on nt 4.0 rus.(i think relocations problem is the point,but i have no
another WIN32 OS for debugging.
3.using of Sleep api sucks,i know and i know now how to do this right way.
4. i have not eliminated nagscreen .it is possible.
5. my skills in writing assembler and writing English sucks either.so what?
6. The program http://www.mtu-net.ru/radmin/ is great, netbus and BO is far behind it, it coasts only 25$
and it can be turn back online by resetting clocks back.(and must be by reinstalling).
7. DMITRI ZNOSHKO is a good programmer it is no doubt that reversing the program to use it
was not worth $25.
8. thanks to fravia,ORC,and other teachers and publishers ,who shown me the way to RE art.
(c) 1999 Staier from http://staier.cjb.net -mainly russian site