Jump to content
Tuts 4 You

How to walk through resource directory?


LCF-AT

Recommended Posts

Posted

Hi guys,

I am trying to read the resources directory of any target to read the whole content inside but now I have the problem that I dont understand it yet correctly using the structs for them.

Example: Below the structs I found for resources

IMAGE_RESOURCE_DIRECTORY STRUCT
    Characteristics dd      ?
    TimeDateStamp dd        ?
    MajorVersion dw         ?
    MinorVersion dw         ?
    NumberOfNamedEntries dw ?
    NumberOfIdEntries dw    ?
IMAGE_RESOURCE_DIRECTORY ENDS

IMAGE_RESOURCE_DIRECTORY_ENTRY STRUCT
    union
        rName	RECORD NameIsString:1,NameOffset:31
        Name1 dd ?
        Id dw ?
    ends
    union
        OffsetToData dd ?
		  rDirectory	RECORD DataIsDirectory:1,OffsetToDirectory:31
    ends
IMAGE_RESOURCE_DIRECTORY_ENTRY ENDS

IMAGE_RESOURCE_DIRECTORY_STRING STRUCT
    Length1 dw      ?
    NameString db   ?
IMAGE_RESOURCE_DIRECTORY_STRING ENDS

IMAGE_RESOURCE_DIR_STRING_U STRUCT
    Length1 dw      ?
    NameString dw   ?
IMAGE_RESOURCE_DIR_STRING_U ENDS

IMAGE_RESOURCE_DATA_ENTRY STRUCT
    OffsetToData dd ?
    Size1 dd        ?
    CodePage dd     ?
    Reserved dd     ?
IMAGE_RESOURCE_DATA_ENTRY ENDS

Now the first start of resources....

$ ==>    00D77000 <Characteristics>        00000000
$+4      00D77004 <TimeDateStamp>          00000000
$+8      00D77008 <MajorVersion>           00000000
$+C      00D7700C <NumberOfNamedEntries>   00070000
$+10     00D77010 <Id>                     00000002  1
$+14     00D77014 <OffsetToData>           80000048
$+18     00D77018                          00000003  2
$+1C     00D7701C                          80000060
$+20     00D77020                          00000005  3
$+24     00D77024                          800000F8
$+28     00D77028                          0000000A  4
$+2C     00D7702C                          80000130
$+30     00D77030                          0000000E  5
$+34     00D77034                          80000148
$+38     00D77038                          00000010  6
$+3C     00D7703C                          800001D8
$+40     00D77040                          00000018  7
$+44     00D77044                          800001F0

Thats the first one.So it means there are 7 main IDs 1-7.Ok so far.Now I take the first one which has ID of 2 = RT_BITMAP and OffsettoData = 48....there I see this..

$+48     00D77048                          00000000
$+4C     00D7704C                          00000000
$+50     00D77050                          00000000
$+54     00D77054                          00010000
$+58     00D77058                          000000C9
$+5C     00D7705C                          80000208

I see one entry followed by C9 = 201 name followed by offset 208

$+208    00D77208                          00000000
$+20C    00D7720C                          00000000
$+210    00D77210                          00000000
$+214    00D77214                          00010000
$+218    00D77218                          00000409
$+21C    00D7721C                          000005F8

Here I see 409 but I am not sure what this is now and 5F8 = again offset.

$+5F8    00D775F8                          00018BB8
$+5FC    00D775FC                          00000E28

First is RVA and second is size of resource.

Anyhow I got problems with that to check that for 100 % and I also just use IMAGE_RESOURCE_DIRECTORY & IMAGE_RESOURCE_DIRECTORY_ENTRY here.So could anyone explain that a little for me?Also how to walk by this arrays.Not sure yet how a code should look like to walk by entire resources etc.

Thank you

Posted

* 0x409 is the language of the resource (0x409 = 1033 = United States (US)). See https://msdn.microsoft.com/en-us/library/windows/desktop/dd318693(v=vs.85).aspx for reference

https://blog.kowalczyk.info/articles/pefileformat.html - Figure 2 is the best explanation of the resource tree that I've seen so far. The entire section about resources is worth reading, too. Or you can look at https://github.com/corkami/pics/blob/master/binary/pe102/pe102.pdf

 

 

  • Like 1
Posted

Hi again,

I have another small question about the 2 structs I have to use for resources using NameEntrys.I am not sure how to check whether ASCII or Unicode is used.

Example:

$ ==>    00788000   00000000
$+4      00788004   497B7549
$+8      00788008   00000000
$+C      0078800C   000A0002

NumberOfIdEntries    = 0002
NumberOfNamedEntries = 000A

$+10     00788010   80002560
$+14     00788014   80000070

NameOffset   = 2560
NameIsString = ?
OffsetToData = 80000070 - 80000000 = 70


IMAGE_RESOURCE_DIRECTORY_ENTRY STRUCT
    union
        rName	RECORD NameIsString:1,NameOffset:31
        Name1 dd ?
        Id dw ?
    ends
    union
        OffsetToData dd ?
        rDirectory  RECORD DataIsDirectory:1,OffsetToDirectory:31
    ends
IMAGE_RESOURCE_DIRECTORY_ENTRY ENDS


$+2560   00480008  ASCII "ollections"

Length1    = 0008
NameString = 0048

$+2560   08 00 48 00 45 00 4C 00 50 00 54 00 45 00 58 00  .H.E.L.P.T.E.X.
$+2570   54                                               T


IMAGE_RESOURCE_DIRECTORY_STRING STRUCT
    Length1 dw      ?
    NameString db   ?
IMAGE_RESOURCE_DIRECTORY_STRING ENDS

IMAGE_RESOURCE_DIR_STRING_U STRUCT
    Length1 dw      ?
    NameString dw   ?
IMAGE_RESOURCE_DIR_STRING_U ENDS

So have I check that by myself whether its ASCII or Unicode or can I see this already in the struct above?How to use the structs with Record x:1 or y:31 like rName / rDirectory?In WInASM I do fail trying to use rName anyhow etc.Also dont check that 1 or 31 thing.Has it something to do with that 8 value at the beginnig or so?

PS: The pdf picture from your link is really good.Nice to have all at one view. :)

greetz

Posted (edited)

1) Resource name is always in Unicode. 

2) As for inability to address rName/rDirectory - those structures are defined incorrectly in the windows.inc distributed with MASM32. Specifically, they mixed up record definitions and record declarations (refer to http://www.sxlist.com/techref/language/masm/masmc05.htm, chapter "Records" for more information).

Because of that, you can't really use them without ugly hacks.

If you fix windows.inc like this:

rrName	RECORD NameIsString:1,NameOffset:31
rrDirectory	RECORD DataIsDirectory:1,OffsetToDirectory:31
IMAGE_RESOURCE_DIRECTORY_ENTRY STRUCT
    union
        rName rrName <>
        Name1 dd ?
        Id dw ?
    ends
    union
        OffsetToData dd ?
        rDirectory rrDirectory <>
    ends
IMAGE_RESOURCE_DIRECTORY_ENTRY ENDS

then you can write pretty code like this:

    ; eax contains address of IMAGE_RESOURCE_DIRECTORY_ENTRY.
    
    ; check if resource name is a string or not..
    mov ecx, (IMAGE_RESOURCE_DIRECTORY_ENTRY PTR [eax]).rName
    and ecx, mask NameIsString
    jne @name_is_string
@name_is_not_string:

but considering the amount of work required to make it work, I wouldn't bother with it...

Edited by kao
  • Like 1
Posted

Hi,

thanks again for these infos kao.I got it working now to get all resources in my tree.Now I would like also to show the resources (icons / cursors / etc),so is there maybe any function I could use what does handle this already just if I send some paramters like ID / Name / icon / bitmap / window handle etc of the resources xy to let display it?Just asking before I try to code all of them one by one to display all.

PS: One another question.Do you know any windows 7 or any else PE file who is using a Exception Directory?So I didnt found any file yet to see how it looks like.Maybe anyone know some filenames I could check out to see it also in debugger.

Thanks again

Posted

1) LoadBitmap, LoadImage, etc.. MSDN is your friend.
2) Any 64 bit application, it's usage is mandatory there.. In x86 world that directory is not used in any way.

  • Like 1
Posted

Hi,

ah ok so only in x64 used.No wonder that I didnt found  any file using it.

Ok,so I try now to show the resources / preview etc.So I think about it to use a static control to set icons / bitmaps etc on it but I think it will not work with all res types to preview them on it.I have a tiny question about the control styles I need to change before putting a icon / bitmap etc on it.So I use GetWindowLong GWL_STYLE to get the style and using SetWIndowLong with new style.Just wanna know how to handle the value I got from GetWIndowStyle.Using or / and / xor commands if I need to enable some styles and disable some styles again etc.How was is going right again?Or should I better use static values like or eax, SS_ICON or SS_CENTERIMAGE or WS_CHILD or WS_VISIBLE?

greetz

Posted

I would use an imagelist control and add the resources as bitmaps or icons to the imagelist, then use a listview to display the bitmaps in tile/icon view.

  • Like 1
Posted

Hi,

ok thanks for that info fearless.One more question.So now I see that I have a problem to load the resources of any file I have mapped in memory and using functions like LoadBitmap.I tried to use the mapped base of loaded target but it seems to fail.So how can I load them now from the mapped files?

greetz

Posted

Hi,

thanks for that infos but I dont like that ones.I would better use any else method loading resources also from mapped files.So I thought it would be already possible to do that.Do you have maybe any another / other ideas about that?

greetz

Posted

lazy / easy way could be using LoadLibraryEx on the file instead of mapping it, and loading it as a data file, thus making the resources (hopefully accessible) with the usual resource api's.. 

 

  • Like 1
Posted

I have a C++ project for this task but I think you are only using ASM so it may not be interesting to you.

but it's definitely easier to use C++ for this task.

  • Like 1
Posted

Hey guys,

thanks for that good info.Using LoadLibraryEx with that LOAD_LIBRARY_AS_DATAFILE flag does work using after the basic LoadBitmap function etc.Now I get them all displayed as I wanted.Thats cool.I still dont check yet whats the diffrent is between my mapped file and the file which was loaded via LLEX as datafile.So both look same in memory same (not using virtual sizes).Is it then not also possible to load that file on same way with CreateFile / CreateFileMapping anyhow?

PS: The LoadLibraryEx function has one disadvantage.So if I load the file in any app like LordPE then LLEX does fail to load it into memory if the file dosent run as own process etc you know (maybe not so important).

Thanks again for that info.

Posted

Hi its me again with a small else question,

I have a little problem with my treeview control I do use.So I try to get all items in treeview using TVM_GETCOUNT and it returns the value and now I try to use TVM_GETITEM to get the text or lparam etc but here I get always 0 back and not 1.Could anyone check what I did wrong?

            invoke SendMessage,hwndTreeView,TVM_GETCOUNT,0,0
            .if eax != 0h
                mov esi,eax

                invoke RtlZeroMemory,addr TVI,sizeof TVI
                mov     TVI.cchTextMax,sizeof TEXTBUFF
                lea eax,TEXTBUFF
                mov		TVI.pszText,eax
                mov		TVI._mask, TVIF_TEXT ;or TVIF_HANDLE;or TVIF_PARAM or TVIF_HANDLE
                invoke SendMessage,hwndTreeView,TVM_GETITEM,0,addr TVI
                .if eax == TRUE
                .endif
            .endif

Just wanna loop later the whole tree / all items to check lparam (to see whether I did store some memory there and free it).Above I tried it first with some text to get something but it fails.Not sure what I did wrong yet.Do you see the problem?

greetz

Posted

Need to provide a hItem for TVITEM for TVM_GETITEM to work and thus you'll need to include TVIF_HANDLE in the TVITEM.mask (_mask) for it to do anything as well.

As you zero out TVITEM (TVI), then hItem is 0 (NULL) and so no text is fetched as there is no node specified just NULL.

 

  • Like 1
Posted

Hi,

ah ok.Thanks.Ok now I have something what seems to work but have again some trouble check all entrys of whole tree with CHILDRENs if CHILDREN items have another CHILDRENs inside.So its again anyhow confusing for me to loop them anyhow correctly.I got something like this so far...

            invoke SendMessage,hwndTreeView,TVM_GETCOUNT,0,0
            .if eax != 0h
                mov esi,eax
                invoke SendMessage,hwndTreeView,TVM_GETNEXTITEM,TVGN_ROOT,0
                .if eax != 0
                    mov esi,eax
                    mov   hItem,eax
                    invoke RtlZeroMemory,addr TVI,sizeof TVI
                    mov     TVI.cchTextMax,sizeof TEXTBUFF
                    lea eax,TEXTBUFF
                    mov		TVI.pszText,eax
                    mov     TVI.hItem,esi
                    mov		TVI._mask, TVIF_TEXT or  TVIF_CHILDREN or TVIF_PARAM
                    .while (hItem != NULL)
                        invoke SendMessage,hwndTreeView,TVM_GETITEM,0,addr TVI
                        .if TVI.cChildren
                             invoke SendMessage,hwndTreeView,TVM_GETNEXTITEM,TVGN_CHILD,hItem

                             
                             
                        .endif
                         invoke  SendMessage,hwndTreeView, TVM_GETNEXTITEM,TVGN_NEXT,hItem
                          mov   hItem,eax
                    
                    
                    .endw
                .endif
            .endif

...do have any hint how I could loop the while tree?

greetz

Posted (edited)

With recursion.

I wrote a function to do just that in my treeview library: https://github.com/mrfearless/libraries/blob/master/Treeview/Treeview x86/TreeViewWalk.asm

so something like:

Invoke TreeViewWalk, hTV, hItem, Addr MyTreeViewCallback, 0

Then create your callback function and prototype for it

MyTreeViewCallback  PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD

MyTreeViewCallback PROC hTreeview:DWORD, hItem:DWORD, dwStatus:DWORD, dwTotalItems:DWORD, dwItemNo:DWORD, dwLevel:DWORD, dwCustomData:DWORD

    ; do some processing

    mov eax, TRUE

    ret

MyTreeViewCallback  ENDP

 

dwStatus is from Treeview.inc:
 

; TreeView Walk Callback Status (dwStatus):
TREEVIEWWALK_NULL EQU 0
TREEVIEWWALK_ITEM EQU 1
TREEVIEWWALK_ITEM_START EQU 2
TREEVIEWWALK_ITEM_FINISH EQU 3
TREEVIEWWALK_ROOT_START EQU 4
TREEVIEWWALK_ROOT_FINISH EQU 5

 

Edited by fearless
update example
  • Like 1
Posted

Hi fearless,

thanks again for that infos.So I see I got some older inc files of your treeview where this walk wasnt present.I updated the inc / lib from you now and wrote some code and it seems to work now. :)

.data?
hItem dd ?

    .elseif uMsg==WM_CLOSE

            invoke SendMessage,hwndTreeView,TVM_GETCOUNT,0,0
            .if eax != 0h
                invoke SendMessage,hwndTreeView,TVM_GETNEXTITEM,TVGN_ROOT,0
                .if eax != 0
                    mov hItem,eax
                    .while hItem != 0h
                    Invoke TreeViewWalk, hwndTreeView, eax, Addr MyTreeViewCallback, 0
                    invoke  SendMessage,hwndTreeView, TVM_GETNEXTITEM,TVGN_NEXT,hItem
                    mov hItem,eax
                    .endw
                .endif
            .endif





MyTreeViewCallback PROC hTreeview:DWORD, hItem:DWORD, dwStatus:DWORD, dwTotalItems:DWORD, dwItemNo:DWORD, dwLevel:DWORD, dwCustomData:DWORD

LOCAL item :TVITEM
local szBuffer [256]:BYTE
    ; do some proces?sing

    
    invoke RtlZeroMemory,addr item,sizeof item
    mov   item.lParam, 0
    m2m   item.hItem,hItem
    mov   item.imask,TVIF_TEXT or TVIF_CHILDREN or TVIF_PARAM
    lea eax,szBuffer
    mov   item.pszText, eax
    mov   item.cchTextMax,MAX_PATH
    invoke   SendMessage,hTreeview, TVM_GETITEM, 0, addr item
    .if item.lParam != 0h
        invoke GetProcessHeap
        invoke HeapFree,eax,NULL,item.lParam
    .endif  
   
    nop
    nop
    nop
    mov eax, TRUE

    ret

MyTreeViewCallback  ENDP

Just wanna check for lparam at the moment to free my memory stuff I did set before.So could you maybe tell some more about the paramters I get at my callback and also at your walk function / lpCustomData etc?Just to know it better and how to use it more correctly also for the future.

PS: That walk thing is really a PITA if they are used tons of childs / nodes and more and more etc you know what I mean.So I think I wouldnt get that coded manually by myself without to get total confused. :)

Thanks again so far.

Posted

The custom data is just that in case you have to pass on some other handle, variable or structure that you might need with processing whilst inside the callback function, if not then just ignore it, leave it at 0.

lParam can be got with the TVM_GETITEM, just reference it, like mov eax, item.lparam

I used the TreeViewWalk in the cjsontree example for the cjson lib, and constructed the walk with that functionality or something like that for future use, so the parameters that get returned in the callback are just information, might be useful or not, depends on the circumstances i guess, Total Items same as TVM_GETITEMCOUNT, item number is current iteration of the items retrieved/walked so far (could use it to do a progress status with total items | current item type thing). the dwLevel is an indication of the distance from root, going into a child with increase level, then another child below with increase level again, coming back out of the children, the level is decremented each time, until back at the root level. Again could be useful for processing or not, depends on whats required.

Yep it took a bit of time to get the treewalk function working, dont think there is another other way of properly and efficiently iterating through all treeview items (when the content is not known and items and children can be added/removed), so recursion is the way in this case.

Hope it helps

  • Like 1
Posted

Hi again,

I have another question about loading and showing the resources of RT_CURSOR,RT_BITMAP,RT_ICON,RT_GROUP_CURSOR,RT_GROUP_ICON.So I have some trouble to show them all on a static control.Some are working some not.Not sure why at the moment.My code looks like this.

                      .if     TREE_RESOURCES_DATAS.RT[edi] == 0h ; just some name no ID
                      
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      .elseif TREE_RESOURCES_DATAS.RT[edi] == RT_BITMAP
                              .if TREE_RESOURCES_DATAS.filename[edi] == 0h ; mach ID
                                  invoke LoadBitmap,DATAHANDLE,TREE_RESOURCES_DATAS.ID[edi]
                                  mov edi,eax
                              .else
                                  invoke LoadBitmap,DATAHANDLE,addr TREE_RESOURCES_DATAS.filename[edi]
                                  mov edi,eax
                              .endif
                              invoke GetDlgItem,hWnd,IDC_STATIC
                              mov esi,eax
                              invoke SetWindowLong,esi,GWL_STYLE,SS_BITMAP or SS_CENTERIMAGE or WS_CHILD or WS_VISIBLE
                              invoke SendMessage,esi,STM_SETIMAGE,IMAGE_BITMAP,edi
                              invoke DeleteObject,edi
                              
                      .elseif TREE_RESOURCES_DATAS.RT[edi] == RT_ICON || TREE_RESOURCES_DATAS.RT[edi] == RT_GROUP_ICON
                              .if TREE_RESOURCES_DATAS.filename[edi] == 0h ; mach ID
                                  ;invoke LoadIcon,DATAHANDLE,TREE_RESOURCES_DATAS.ID[edi]
                                  invoke LoadImage,DATAHANDLE,TREE_RESOURCES_DATAS.ID[edi],IMAGE_ICON,0,0,LR_DEFAULTSIZE
                                  mov edi,eax
                              .else
                                  ;invoke LoadIcon,DATAHANDLE,TREE_RESOURCES_DATAS.filename[edi]
                                  invoke LoadImage,DATAHANDLE,TREE_RESOURCES_DATAS.ID[edi],IMAGE_ICON,0,0,LR_DEFAULTSIZE
                                  mov edi,eax
                              .endif
                              invoke GetDlgItem,hWnd,IDC_STATIC
                              mov esi,eax
                              invoke SetWindowLong,esi,GWL_STYLE,SS_ICON or SS_CENTERIMAGE or WS_CHILD or WS_VISIBLE
                              invoke SendMessage,esi,STM_SETIMAGE,IMAGE_ICON,edi
                              invoke DestroyIcon,edi
                      .elseif TREE_RESOURCES_DATAS.RT[edi] == RT_CURSOR || TREE_RESOURCES_DATAS.RT[edi] == RT_GROUP_CURSOR
                              .if TREE_RESOURCES_DATAS.filename[edi] == 0h ; mach ID
                                  invoke LoadCursor,DATAHANDLE,TREE_RESOURCES_DATAS.ID[edi]
                                  mov edi,eax
                              .else
                                  invoke LoadCursor,DATAHANDLE,TREE_RESOURCES_DATAS.filename[edi]
                                  mov edi,eax
                              .endif
                              invoke GetDlgItem,hWnd,IDC_STATIC
                              mov esi,eax
                              invoke SetWindowLong,esi,GWL_STYLE,SS_ICON or SS_CENTERIMAGE or WS_CHILD or WS_VISIBLE
                              invoke SendMessage,esi,STM_SETIMAGE,IMAGE_CURSOR,edi
                              invoke DestroyCursor,edi
                      .endif

RT_BITMAP and RT_GROUP_ICON and RT_GROUP_CURSOR are working to show them but the others show nothing.Wonder why RT_ICON and RT_CURSOR  dosent show something if RT_GROUP_ICON and RT_GROUP_ICON  does work!?Anyway,so the curosrs also dosent work.Does anyone see whats wrong above?

PS: Also would like to handle that SetWindowLong anyhow else so I think it makes also any problem using it so.Any hints are welcome.

Thank you

Posted

Could try taking out the default size for icons and setting a specific size - let it scale the icon for you.

Check if the return from LoadImage returns something in eax when loading the icons

Cursors are very similar to icons, but might not be similar enough for  SS_ICON style, so might have to extract/convert the cursor to an icon first, might have use GetIconInfo, then change some stuff in the structure it uses and then use CreateIconIndirect. Also check the return from LoadCursor to see if eax contains something valid first. Or try using LoadImage with type IMAGE_CURSOR first to see if that loads it up correctly.

  • Like 1
Posted

Hi,

so I see the problem is that I cant use these functions like LoadIcon / LoadCursor / Image etc for RT_ICON and RT_CURSOR so with these I need to use the resource ID or Name and thats the reason why the Groups are working = IDs inside and in the not Groups are just some kind of index values / names 1,2,3,4, etc which are no IDs.The question now is how to load this resources.I tried to use FindResource / LoadResource / LockResource which seems to work but what then?How to use this handle now so I cant use it with the functions like LoadIcon etc.Do you have an idea?

greetz

Posted

Hi again,

ok I got it now. :) RT_BITMAP / RT_ICON / RT_GROUP_ICON / RT_CURSOR &  RT_GROUP_CURSOR.All showing now on my static control.For the none groups RT_ICON & RT_CURSOR I use FindResource etc and using it at the end with CreateIconFromResource function for icon or cursor (True / fals) and VOS_OS232.Seems to be fine so far for that resources types to show them.Will see what I do with the resources types to do same anyhow to show them.

greetz

Posted

Its me again,

now I tried to handle RT_STRING using LoadString function but it fails and I get the error ERROR_RESOURCE_NAME_NOT_FOUND.Why this?Just using LoadString with hInstance,ID,buffer,sizeof buffer.Just fails.

2018-07-03_152549.png.4b66680381c3430e9db493887b856ed1.png

001FDE48   00E9B2B8  /CALL to LoadStringA from bones.00E9B2B3
001FDE4C   03BF0001  |hInst = 03BF0001
001FDE50   00000FD9  |RsrcID = FD9 (4057.)
001FDE54   00E60000  |Buffer = 00E60000
001FDE58   00010000  \Count = 10000 (65536.)
EAX 00000000
ECX 7FFDF000
EDX 00000716
EBX 00000000
ESP 001FDE5C
EBP 001FE03C
ESI 00E60000
EDI 00000FD9
EIP 00E9B2B8 bones.00E9B2B8
C 0  ES 0023 32bit 0(FFFFFFFF)
P 1  CS 001B 32bit 0(FFFFFFFF)
A 0  SS 0023 32bit 0(FFFFFFFF)
Z 1  DS 0023 32bit 0(FFFFFFFF)
S 0  FS 003B 32bit 7FFDF000(4000)
T 0  GS 0000 NULL
D 0
O 0  LastErr ERROR_RESOURCE_NAME_NOT_FOUND (00000716)

LoadStringW also fails if I need to use this.Does anyone know the problem for that?

greetz

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...