Registration Code (Part 1): w%kQ6
Registration Code (Part 2): b<#$1[*(cw~
In order to register on this forum, you must use the codes above. Combine them into one code (copy paste).

Echo of Soul .ini Decryption

Have a release that does not fit elsewhere? Post it here!
Post Reply
User avatar
atom0s
Site Admin
Posts: 400
Joined: Sun Jan 04, 2015 11:23 pm
Location: 127.0.0.1
Contact:

Echo of Soul .ini Decryption

Post by atom0s » Fri Dec 04, 2015 11:38 pm

Echo of Soul is an MMORPG I have started to play in my free time given that Diablo 3 is being ran into the ground with the current development team. That said, I was interested in seeing some of the file contents of this game so I sought into getting things unprotected.

To start, the main game executable (and several other files) are protected with Themida. I'm not going to cover how to unpack that since there are plenty of tutorials on the net for that. It's nothing special and easily removed with some automated scripts/tools.

Once unpacked, I dug around for the routines that handle the ini files. After some digging, I discovered that EoS is using a custom bit of xor'ing and using Microsoft's Enhanced Cryptographic provider.

First, I found the creation of the provider. This setups up the needed hash/key and provider objects needed to do the decryption and encryption of the data. The setup they do is as follow:
  1. if ( !CryptAcquireContextW(
  2.       (HCRYPTPROV *)(a1 + 4208),
  3.       L"SBENCRYPTIONKEYCONTAINER10",
  4.       L"Microsoft Enhanced Cryptographic Provider v1.0",
  5.       1u,
  6.       0)
  7. && GetLastError() == 0x80090016 )
  8. CryptAcquireContextW((HCRYPTPROV *)(a1 + 4208), L"SBENCRYPTIONKEYCONTAINER10", 0, 1u, 8u);
  9. if ( !*(_DWORD *)(a1 + 4208) )
  10. {
  11. v4 = GetLastError();
  12. sub_E4B130(L"CryptAcquireContext failed. %08x", v4);
  13. }
  14. v5 = (HCRYPTHASH *)(a1 + 4216);
  15. if ( CryptCreateHash(*(_DWORD *)(a1 + 4208), 0x8003u, 0, 0, (HCRYPTHASH *)(a1 + 4216))
  16. && CryptHashData(*v5, &pbData, 8u, 0)
  17. && CryptDeriveKey(*(_DWORD *)(a1 + 4208), 0x6801u, *v5, (DWORD)&loc_800000, (HCRYPTKEY *)(a1 + 4212)) )
  18. v9 = 0;
  19. else
  20. LOBYTE(v9) = 0;
  21. return a1;
Digging some more we find the function that makes use of the provider created. This function does a bit more work though to ensure the files are proper and not tampered with.
  1. v2 = (const CHAR *)sub_E2DF80(lpFileName);
  2.   v3 = CreateFileA(v2, 0x80000000, 1u, 0, 3u, 0x80u, 0);
  3.   if ( v3 == (HANDLE)-1
  4.     || (NumberOfBytesRead = 0,
  5.         v9 = 0xD0B7A0CC,
  6.         ReadFile(v3, Buffer, 4u, &NumberOfBytesRead, 0),
  7.         CloseHandle(v3),
  8.         NumberOfBytesRead != 4) )
  9.   {
  10. LABEL_8:
  11.     result = 0;
  12.   }
  13.   else
  14.   {
  15.     for ( i = 0; ; ++i )
  16.     {
  17.       v7 = i;
  18.       if ( i >= 4 )
  19.         break;
  20.       if ( Buffer[i] != *((_BYTE *)&v9 + i) )
  21.         goto LABEL_8;
  22.     }
  23.     result = 1;
  24.   }
  25.   return result;
In this function the file is loaded and the first 4 bytes are read. They are checked against the key '0xD0B7A0CC'. If that key does not exist or is different, the file is considered tampered with and will not load.

Afterward, the file is then decrypted using:
  1. NumberOfBytesRead = 0;
  2.       ReadFile(*(HANDLE *)(v4 + 88), (LPVOID)(v4 + 116), 0x400u, &NumberOfBytesRead, 0);
  3.       if ( (signed int)NumberOfBytesRead >= 8 )
  4.       {
  5.         v23 = NumberOfBytesRead >> 3;
  6.         do
  7.         {
  8.           sub_409810(*(_DWORD *)(v4 + 1144), v13);
  9.           v13 += 8;
  10.           --v23;
  11.         }
  12.         while ( v23 );
  13.       }
Here the app reads 0x400 bytes of the file in at a time, and then handles 8 bytes at a time to decrypt. The decryption is done with the sub_409810 call. That call is as follows:
  1. int __usercall sub_409810@<eax>(HCRYPTKEY hKey@<ecx>, int a2@<esi>)
  2. {
  3.   signed int v2; // ecx@1
  4.   int v3; // eax@2
  5.   int result; // eax@3
  6.   int v5; // [sp+0h] [bp-4h]@1
  7.  
  8.   v5 = 8;
  9.   CryptDecrypt(hKey, 0, 1, 0, (BYTE *)a2, (DWORD *)&v5);
  10.   v2 = 0;
  11.   do
  12.   {
  13.     LOBYTE(v3) = *(_BYTE *)(v2 + a2);
  14.     if ( (_BYTE)v3 == 127 )
  15.     {
  16.       result = 0;
  17.     }
  18.     else if ( (_BYTE)v3 == -128 )
  19.     {
  20.       result = 255;
  21.     }
  22.     else
  23.     {
  24.       v3 = (unsigned __int8)v3;
  25.       if ( (unsigned __int8)v3 >= 0x80u )
  26.         result = v3 - 1;
  27.       else
  28.         result = v3 + 1;
  29.     }
  30.     *(_BYTE *)(v2++ + a2) = result;
  31.   }
  32.   while ( v2 < 8 );
  33.   *(_DWORD *)a2 ^= 0xA4A7FF88;
  34.   *(_DWORD *)(a2 + 4) ^= 0xA0447823;
  35.   return result;
  36. }
So we can see that the game has a rundown of the following:
- Create the crypto provider for decryption.
- Read the first 4 bytes of the file and look for the key: 0xD0B7A0CC
- Loop the file data and decrypt it.
- Xor the decrypted data with the keys: 0xA4A7FF88 and 0xA0447823

And then at that point we now have the decrypted file. For example the EoS.ini file is encrypted, running it through this will give us the full file which looks like:
  1. [URL]
  2. Protocol=EOS
  3. ProtocolDescription=EOS Protocol
  4. Name=Player
  5. Map=Index.unr
  6. LocalMap=Entry.unr
  7. LobbyMap=Lobby.unr/Lobby_rogue.unr/Lobby_guardian.unr/Lobby_sorceress.unr/Lobby_warrior.unr/Lobby_archer.unr/Lobby_Warlock.unr
  8. NetBrowseMap=Entry.unr
  9. Portal=
  10. MapExt=unr
  11. EXEName=EOS.exe
  12. SaveExt=usa
  13. Class=SBGame.SBRogue
  14. Character=SBRogue
  15. HostLogin=192.168.0.103
  16. PortLogin=12567
  17. Host=192.168.0.103
  18. Port=12557
  19. ;Host=112.216.119.206
  20. ;Port=12557
  21. ;Host=192.168.0.202
  22. HostAlpha=119.205.253.232
  23. PortAlpha=11476
  24.  
  25. [SB]
  26. NetLogin=true
  27. NetLoginWorldList=true
  28. BGMOn=true
  29. MultiLangAvailables=EN|DE|FR
  30. MultiLangCode=EN
  31.  
  32. [PubNHN.PubNHNService]
  33. UseSurvey=false
  34. SurveyWindowWidth=400
  35. SurveyWindowHeight=500
  36. CouponWindowX=100
  37. CouponWindowY=100
  38. CouponWindowWidth=600
  39. CouponWindowHeight=479
  40. HomepageURL=http://eos.hangame.com/
  41. SecurityPageURL=http://eos.hangame.com/cs/security.nhn
  42. BannerURL=http://eos.dn.toastoven.net/Banner/
  43. MobileDownloadURL=http://eos.hangame.com/sendSms/popupSendSms.nhn
  44.  
  45. [PubCHN.PubCHNService]
  46. UseSecondPassword=false
  47. UseDamageMeter=false
  48. UseServerNameCheck=true
  49. HomepageURL=http://eos.changyou.com
  50. MembershipPageURL=http://member.changyou.com/registerNoSuffix/index.jsp?gametype=eos
  51. PasswordPageURL=http://member.changyou.com/common/codeAdmin.do
  52. CertificationPageURL=http://account.changyou.com/fangchenmi/submitlogin.jsp
  53. RealNamePageURL=http://account.changyou.com/quickRegister/QuickRegDetail.jsp
  54. CustomerPageURL=http://gm.changyou.com/indexPage.do
  55. SoulMoneyPointPageURL=http://event.changyou.com/eos/201411/pay/index.shtml
  56. GameAgreePageURL=http://member.changyou.com/inc/useragreement.html
  57. BannerURL=http://update.changyou.com/eoscashshop/RecommendItem/
  58. BannerPageURL=http://update.changyou.com/eoscashshop/ActivePage/
  59. MobileDownloadURL=http://event.changyou.com/eos/201409/app/index.shtml
  60. TargetNameScaleMin=0.35
  61. TargetNameScaleStep=0.01
  62.  
  63. [PubTHA.PubTHAService]
  64. SkipXignCode=false
  65. HomepageURL=http://www.eos.in.th
  66. PasswordPageURL=https://auth.gg.in.th/authenticate_v2/ForgotPassword.aspx
  67. MembershipPageURL=https://auth.gg.in.th/authenticate_v2/GGPlatForm_Register.aspx?appid=41
  68. BannerURL=http://eos.gg.in.th/ingame/CashShop/
  69. MobileDownloadURL=http://eos.gg.in.th/gameguide/mobile.aspx
  70.  
  71. [PubJPN.PubJPNService]
  72. SkipXignCode=false
  73.  
  74. [PubEUUS.PubEUUSService]
  75. RechargePMoneyURL=https://billing.aeriagames.com
  76. BannerURL=http://echoofsoul.patch.aeriagames.com/Notice/
  77. SecurityPageURL=http://www.aeriagames.com/contact
  78.  
  79. [FirstRun]
  80. FirstRun=3369
  81.  
  82. [Engine.Engine]
  83. ;Publish=PubNHN.PubNHNService
  84. ;Publish=PubTHA.PubTHAService
  85. ;Publish=PubCHN.PubCHNService
  86. ;Publish=PubJPN.PubJPNService
  87. Publish=PubEUUS.PubEUUSService
  88. ;Publish=Engine.PubNullService
  89. RenderDevice=D3DDrv.D3DRenderDevice
  90. AudioDevice=ALAudio.ALAudioSubsystem
  91. Console=Engine.Console
  92. ;GUIController=SBInterface.SBGUIController
  93. GUIController=GFx4UI.GFx4Controller
  94. Language=int
  95. Product=EOS
  96. GameEngine=Engine.SBGameEngine
  97. EditorEngine=Editor.EditorEngine
  98. ViewportManager=WinDrv.WindowsClient
  99.  
  100. [Core.System]
  101. PurgeCacheDays=30
  102. SavePath=..\Save
  103. CachePath=../Cache
  104. CacheExt=.uxx
  105. CacheRecordPath=../System/*.ucl
  106. MusicPath=../Data/Sounds
  107. MusicPath=../Data/Voices
  108. GUIPath=../Data/UI
  109. Paths=../Data/Textures/*.utx
  110. Paths=../Data/Sounds/*.uax
  111. Paths=../Data/Animations/*.ukx
  112. Paths=../Data/StaticMeshes/*.usx
  113. Paths=../Data/Voices/*.uax
  114. Paths=../Data/Maps/*.unr
  115. Paths=../Data/UI/*.ugx
  116. Paths=../System/*.u
  117. Paths=../Data/Textures/FX/*.utx
  118. Paths=../Data/Textures/Monster/*.utx
  119. Paths=../Data/Animations/Monster/*.ukx
  120. Paths=../Data/Textures/PC/Guardian/*.utx
  121. Paths=../Data/Animations/PC/Guardian/*.ukx
  122. Paths=../Data/Textures/PC/Rogue/*.utx
  123. Paths=../Data/Animations/PC/Rogue/*.ukx
  124. Paths=../Data/Textures/PC/Sorceress/*.utx
  125. Paths=../Data/Animations/PC/Sorceress/*.ukx
  126. Paths=../Data/Textures/PC/Warrior/*.utx
  127. Paths=../Data/Animations/PC/Warrior/*.ukx
  128. Paths=../Data/Textures/PC/Warlock/*.utx
  129. Paths=../Data/Animations/PC/Warlock/*.ukx
  130. Paths=../Data/Textures/PC/Archer/*.utx
  131. Paths=../Data/Animations/PC/Archer/*.ukx
  132. Paths=../Data/Textures/NPC/*.utx
  133. Paths=../Data/Animations/NPC/*.ukx
  134. Paths=../Data/Textures/Etc/*.utx
  135. Paths=../Data/Animations/Etc/*.ukx
  136. Paths=../Data/Textures/Pet/*.utx
  137. Paths=../Data/Animations/Pet/*.ukx
  138. Paths=../Data/Textures/BG/*.utx
  139. Paths=../Data/Animations/BG/*.ukx
  140. Paths=../Data/Animations/Cut/*.ukx
  141. Paths=../Data/Textures/WorldMap/*.utx
  142. Paths=../Data/Textures/L10N/*.utx
  143. Paths=../Data/Textures/UI/*.utx
  144. Paths=../../System/*.u
  145. Paths=../../Data/Maps/*.unr
  146. Paths=../../Data/Textures/*.utx
  147. Paths=../../Data/Textures/FX/*.utx
  148. Paths=../../Data/Sounds/*.uax
  149. Paths=../../Data/Voices/*.uax
  150. Paths=../../Data/StaticMeshes/*.usx
  151. Paths=../../Data/Animations/*.ukx
  152. Paths=../../Data/UI/*.ugx
  153. Paths=../DataNext/Textures/*.utx
  154. Paths=../DataNext/Sounds/*.uax
  155. Paths=../DataNext/Animations/*.ukx
  156. Paths=../DataNext/StaticMeshes/*.usx
  157. Paths=../DataNext/Voices/*.uax
  158. Paths=../DataNext/Maps/*.unr
  159. Paths=../DataNext/UI/*.ugx
  160. Paths=../DataNext/Textures/FX/*.utx
  161. Paths=../DataNext/Textures/Monster/*.utx
  162. Paths=../DataNext/Animations/Monster/*.ukx
  163. Paths=../DataNext/Textures/PC/Guardian/*.utx
  164. Paths=../DataNext/Animations/PC/Guardian/*.ukx
  165. Paths=../DataNext/Textures/PC/Rogue/*.utx
  166. Paths=../DataNext/Animations/PC/Rogue/*.ukx
  167. Paths=../DataNext/Textures/PC/Sorceress/*.utx
  168. Paths=../DataNext/Animations/PC/Sorceress/*.ukx
  169. Paths=../DataNext/Textures/PC/Warrior/*.utx
  170. Paths=../DataNext/Animations/PC/Warrior/*.ukx
  171. Paths=../DataNext/Textures/PC/Archer/*.utx
  172. Paths=../DataNext/Animations/PC/Archer/*.ukx
  173. Paths=../DataNext/Textures/PC/Warlock/*.utx
  174. Paths=../DataNext/Animations/PC/Warlock/*.ukx
  175. Paths=../DataNext/Textures/NPC/*.utx
  176. Paths=../DataNext/Animations/NPC/*.ukx
  177. Paths=../DataNext/Textures/Etc/*.utx
  178. Paths=../DataNext/Animations/Etc/*.ukx
  179. Paths=../DataNext/Textures/Pet/*.utx
  180. Paths=../DataNext/Animations/Pet/*.ukx
  181. Paths=../DataNext/Textures/BG/*.utx
  182. Paths=../DataNext/Animations/BG/*.ukx
  183. Paths=../DataNext/Animations/Cut/*.ukx
  184. Paths=../DataNext/Textures/WorldMap/*.utx
  185. Paths=../DataNext/Textures/L10N/*.utx
  186. Paths=../DataNext/Textures/UI/*.utx
  187. Paths=../../System/*.u
  188. Paths=../../Data/Maps/*.unr
  189. Paths=../../Data/Textures/*.utx
  190. Paths=../../Data/Textures/FX/*.utx
  191. Paths=../../Data/Sounds/*.uax
  192. Paths=../../Data/Voices/*.uax
  193. Paths=../../Data/StaticMeshes/*.usx
  194. Paths=../../Data/Animations/*.ukx
  195. Paths=../../Data/Saves/*.uvx
  196. Paths=../../Data/UI/*.ugx
  197. Suppress=DevLoad
  198. Suppress=DevSave
  199. Suppress=DevNetTraffic
  200. Suppress=DevGarbage
  201. Suppress=DevKill
  202. Suppress=DevReplace
  203. Suppress=DevCompile
  204. Suppress=DevBind
  205. Suppress=DevBsp
  206. Suppress=DevNet
  207. Suppress=RecordCache
  208. Suppress=MapVoteDebug
  209. suppress=MapVote
  210. Suppress=Timer
  211. MusicPath=../Data/Voices/EN
  212. Paths=../Data/Voices/EN/*.uax
  213. Paths=../../Data/Voices/EN/*.uax
  214.  
  215. [Engine.GameEngine]
  216. CacheSizeMegs=32
  217. UseSound=True
  218. UseStaticMeshBatching=false
  219. MainMenuClass=SBInterface.MainMenu
  220. SinglePlayerMenuClass=SBInterface.MainMenu
  221. ConnectingMenuClass=SBInterface.SBLevelLoading
  222. DisconnectMenuClass=
  223. LoadingClass=SBInterface.SBLevelLoading
  224.  
  225. [WinDrv.WindowsClient]
  226. Brightness=0.500000
  227. Contrast=0.500000
  228. Gamma=1.000000
  229. UseJoystick=False
  230. CaptureMouse=False
  231. NoLighting=False
  232. MinDesiredFrameRate=35.000000
  233. AnimMeshDynamicLOD=0.000000
  234. Decals=True
  235. Coronas=True
  236. DecoLayers=True
  237. Projectors=True
  238. NoDynamicLights=False
  239. ReportDynamicUploads=False
  240. TextureDetailInterface=UltraHigh
  241. TextureDetailTerrain=UltraHigh
  242. TextureDetailWeaponSkin=UltraHigh
  243. TextureDetailPlayerSkin=UltraHigh
  244. TextureDetailWorld=UltraHigh
  245. TextureDetailRenderMap=UltraHigh
  246. TextureDetailLightmap=UltraHigh
  247. NoFractalAnim=False
  248. MouseXMultiplier=1.000
  249. MouseYMultiplier=1.000
  250. UseSpeechRecognition=True
  251. WeatherEffects=True
  252. DrawDistanceLOD=1.0
  253.  
  254. [ALAudio.ALAudioSubsystem]
  255. UseEAX=True
  256. Use3DSound=True
  257. UseDefaultDriver=True
  258. MaxEAXVersion=255
  259. UsePrecache=True
  260. ReverseStereo=False
  261. Channels=128
  262. PlaybackLimit=7
  263. MusicVolume=1.00000
  264. AmbientVolume=1.000000
  265. SoundVolume=1.00000
  266. VolumeScaleRec=0.100000
  267. DopplerFactor=1.0
  268. Rolloff=0.5
  269. TimeBetweenHWUpdates=15
  270. DisablePitch=False
  271. LowQualitySound=False
  272. LocalZOffset=0.0
  273.  
  274. [D3DDrv.D3DRenderDevice]
  275. DetailTextures=True
  276. HighDetailActors=True
  277. SuperHighDetailActors=True
  278. UsePrecaching=True
  279. UseTrilinear=True
  280. AdapterNumber=-1
  281. ReduceMouseLag=False
  282. UseTripleBuffering=False
  283. UseHardwareTL=True
  284. UseHardwareVS=True
  285. UseCubemaps=True
  286. DesiredRefreshRate=60
  287. UseCompressedLightmaps=True
  288. UseStencil=False
  289. Use16bit=False
  290. Use16bitTextures=False
  291. MaxPixelShaderVersion=255
  292. LevelOfAnisotropy=1
  293. TesselationFactor=1.0
  294. CheckForOverflow=False
  295. AvoidHitches=False
  296. OverrideDesktopRefreshRate=False
  297. ReportUnusedTextures=False
  298.  
  299. [Editor.EditorEngine]
  300. UseSound=True
  301. CacheSizeMegs=32
  302. GridEnabled=True
  303. SnapVertices=False
  304. SnapDistance=1.000000
  305. GridSize=(X=4.000000,Y=4.000000,Z=4.000000)
  306. RotGridEnabled=True
  307. RotGridSize=(Pitch=1024,Yaw=1024,Roll=1024)
  308. GameCommandLine=-log
  309. FovAngleDegrees=90.000000
  310. GodMode=True
  311. AutoSave=True
  312. AutoSaveTimeMinutes=5
  313. AutoSaveIndex=6
  314. UseAxisIndicator=True
  315. MatineeCurveDetail=0.1
  316. ShowIntWarnings=False
  317. UseSizingBox=True
  318. RenderDevice=D3D9Drv.D3D9RenderDevice
  319. AudioDevice=ALAudio.ALAudioSubsystem
  320. Console=Engine.Console
  321. Language=ute
  322. AlwaysShowTerrain=False
  323. UseActorRotationGizmo=False
  324. LoadEntirePackageWhenSaving=0
  325. EditPackages=Core
  326. EditPackages=Engine
  327. EditPackages=Fire
  328. EditPackages=Editor
  329. EditPackages=UnrealEd
  330. EditPackages=GamePlay
  331. EditPackages=GUI
  332. ;EditPackages=SBScene
  333. ;EditPackages=SBEffect
  334. ;EditPackages=SBGame
  335. ;EditPackages=SBSkillEffect
  336. ;EditPackages=SBInterface
  337. CutdownPackages=Core
  338. CutdownPackages=Editor
  339. CutdownPackages=Engine
  340. CutdownPackages=Fire
  341. CutdownPackages=UnrealEd
  342. CutdownPackages=GamePlay
  343. CutdownPackages=GUI
  344. CutdownPackages=SBEffect
  345. CutdownPackages=SBGame
  346. CutdownPackages=SBSkillEffect
  347.  
  348. [Engine.AmbientSound]
  349. AmbientVolume=0.25
  350.  
  351. [Engine.LevelInfo]
  352. PhysicsDetailLevel=PDL_Medium
  353. MeshLODDetailLevel=MDL_Medium
  354. bLowSoundDetail=False
  355.  
  356. [UnrealEd.UnrealEdEngine]
  357. UseStaticMeshBatching=False
  358.  
  359. [LevelLoadingData]
  360. Entry=37
  361. Sp_Cube_Forest001Map=404
Derp~
Need a great web host? Check out: AnHonestHost.com


Donations can be made via Paypal:
https://www.paypal.me/atom0s
User avatar
atom0s
Site Admin
Posts: 400
Joined: Sun Jan 04, 2015 11:23 pm
Location: 127.0.0.1
Contact:

Re: Echo of Soul .ini Decryption

Post by atom0s » Sun Dec 06, 2015 12:01 am

The file encryption uses the same hash provider data. The setup of encryption is as follows:

Code: Select all

BOOL __usercall sub_4097B0@<eax>(int a1@<edx>, DWORD a2@<ecx>, HCRYPTKEY hKey)
{
  signed int v3; // ecx@1
  unsigned __int8 v4; // al@2
  char v5; // al@3
  DWORD pdwDataLen; // [sp+0h] [bp-4h]@1

  pdwDataLen = a2;
  *(_DWORD *)a1 ^= 0xA4A7FF88;
  *(_DWORD *)(a1 + 4) ^= 0xA0447823;
  v3 = 0;
  do
  {
    v4 = *(_BYTE *)(v3 + a1);
    if ( v4 )
    {
      if ( v4 == -1 )
      {
        v5 = -128;
      }
      else if ( v4 >= 0x80u )
      {
        v5 = v4 + 1;
      }
      else
      {
        v5 = v4 - 1;
      }
    }
    else
    {
      v5 = 127;
    }
    *(_BYTE *)(v3++ + a1) = v5;
  }
  while ( v3 < 8 );
  pdwDataLen = 8;
  return CryptEncrypt(hKey, 0, 1, 0, (BYTE *)a1, &pdwDataLen, 8u);
}
This function is looped with 8 bytes of data at a time:

Code: Select all

    ReadFile(v6, (LPVOID)(a1 + 108), 8u, &NumberOfBytesRead, 0);
    if ( NumberOfBytesRead == 8 )
      sub_4097B0(a1 + 108, v7, *(_DWORD *)(a1 + 4212));
The encryption also writes the signature to the file at the first four bytes. 0xD0B7A0CC
Derp~
Need a great web host? Check out: AnHonestHost.com


Donations can be made via Paypal:
https://www.paypal.me/atom0s
Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest