├── Geek.cs ├── README.md └── demo ├── App.config ├── Geek.cs ├── Program.cs ├── Properties └── AssemblyInfo.cs ├── demo.csproj ├── demo.sln └── geetest.gif /Geek.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Collections.Generic; 4 | using System.Drawing; 5 | using System.Drawing.Imaging; 6 | using System.IO; 7 | using System.Net; 8 | using System.Threading; 9 | using ServiceStack.Text; 10 | namespace GeetestCrack 11 | { 12 | public class Geek 13 | { 14 | private JsonObject config = null; 15 | private string referer = ""; 16 | private string userAgent = "[your user agent]"; 17 | Random rnd = new Random(); 18 | public string challenge 19 | { 20 | get 21 | { 22 | if (config != null) 23 | return config.Get("challenge"); 24 | else 25 | return ""; 26 | } 27 | private set 28 | { 29 | if (config == null) 30 | config = new JsonObject(); 31 | config["challenge"] = value; 32 | } 33 | } 34 | public string gt 35 | { 36 | get 37 | { 38 | if (config != null) 39 | return config.Get("gt"); 40 | else 41 | return ""; 42 | } 43 | set 44 | { 45 | if (config == null) 46 | config = new JsonObject(); 47 | config["gt"] = value; 48 | } 49 | } 50 | public Geek(string gt = "", string referer = "") 51 | { 52 | if (!string.IsNullOrEmpty(gt)) 53 | this.gt = gt; 54 | if(!string.IsNullOrEmpty(referer)) 55 | this.referer = referer; 56 | GetConfig(); 57 | } 58 | public Geek(Uri uri) 59 | { 60 | string source = ""; 61 | HttpWebRequest hreq = (HttpWebRequest)HttpWebRequest.Create(uri); 62 | HttpWebResponse hres = (HttpWebResponse)hreq.GetResponse(); 63 | using (StreamReader sr = new StreamReader(hres.GetResponseStream())) 64 | source = sr.ReadToEnd(); 65 | hres.Close(); 66 | var obj = JsonObject.Parse(source); 67 | this.gt = obj.Get("gt"); 68 | this.referer = uri.Host; 69 | challenge = obj.Get("challenge"); 70 | GetConfig(); 71 | } 72 | 73 | public void GetConfig() 74 | { 75 | if (string.IsNullOrEmpty(gt)) 76 | return; 77 | var getUrl = string.Format("http://api.geetest.com/get.php?gt={0}&challenge={1}&product=embed&offline=false", gt, challenge); 78 | Uri uri = new Uri(getUrl); 79 | HttpWebRequest hreq = (HttpWebRequest)HttpWebRequest.Create(uri); 80 | hreq.Timeout = 10000; 81 | hreq.Referer = this.referer; 82 | hreq.CookieContainer = new CookieContainer(); 83 | HttpWebResponse hres = (HttpWebResponse)hreq.GetResponse(); 84 | var cookies = hreq.CookieContainer.GetCookieHeader(uri); 85 | string js = ""; 86 | using (StreamReader sr = new StreamReader(hres.GetResponseStream())) 87 | js = sr.ReadToEnd(); 88 | hres.Close(); 89 | 90 | var sIndex = js.IndexOf("new Geetest({"); 91 | if (sIndex < 1) 92 | return; 93 | var eIndex = js.IndexOf("},true)", sIndex); 94 | if (eIndex < sIndex) 95 | return; 96 | var json = js.Substring(sIndex + 12, eIndex - sIndex - 11); 97 | 98 | config = JsonObject.Parse(json); 99 | config["cookie"] = cookies; 100 | config["initchallenge"] = config["challenge"]; 101 | //Console.WriteLine("config: " + config.Dump()); 102 | } 103 | 104 | public bool RefreshConfig() 105 | { 106 | if (string.IsNullOrEmpty(gt)) 107 | return false; 108 | var refreshUrl = string.Format("http://api.geetest.com/refresh.php?gt={0}&challenge={1}&callback=cb", gt, challenge); 109 | Uri uri = new Uri(refreshUrl); 110 | string js = ""; 111 | try 112 | { 113 | HttpWebRequest hreq = (HttpWebRequest)HttpWebRequest.Create(uri); 114 | hreq.Timeout = 10000; 115 | hreq.Referer = this.referer; 116 | hreq.CookieContainer = new CookieContainer(); 117 | var cookies = config.Get("cookie"); 118 | hreq.CookieContainer.SetCookies(uri, cookies); 119 | HttpWebResponse hres = (HttpWebResponse)hreq.GetResponse(); 120 | using (StreamReader sr = new StreamReader(hres.GetResponseStream())) 121 | js = sr.ReadToEnd(); 122 | hres.Close(); 123 | } 124 | catch(Exception ex) 125 | { 126 | //Console.WriteLine("refresh error: " + ex.Message); 127 | challenge = config["initchallenge"]; 128 | } 129 | 130 | if (string.IsNullOrEmpty(js)) 131 | return false; 132 | var json = js.Substring(3, js.Length - 4); 133 | 134 | var newParams = JsonObject.Parse(json); 135 | config["ypos"] = newParams["ypos"]; 136 | config["challenge"] = newParams["challenge"]; 137 | config["bg"] = newParams["bg"]; 138 | config["fullbg"] = newParams["fullbg"]; 139 | config["slice"] = newParams["slice"]; 140 | //Console.WriteLine("config refreshed: " + config.Dump()); 141 | return true; 142 | } 143 | 144 | public JsonObject GetValidate() 145 | { 146 | // load images 147 | var imgUrlBase = string.Format("http://{0}", config.Get("staticservers")[0]); 148 | Image bg = LoadImage(imgUrlBase + config.Get("bg")); 149 | Image full = LoadImage(imgUrlBase + config.Get("fullbg")); 150 | int ypos = config.Get("ypos") + 3; 151 | bg = AlignImage(bg, ypos); 152 | full = AlignImage(full, ypos); 153 | 154 | // get position 155 | int xpos = GetPositionX(bg, full); 156 | config["xpos"] = xpos.ToString(); 157 | var actions = GetActions(xpos); 158 | //Console.WriteLine("xpos: " + xpos); 159 | // try actions 160 | var cookies = config.Get("cookie"); 161 | foreach(var action in actions) 162 | { 163 | xpos = action.Get("pos"); 164 | //Console.WriteLine("try pos: " + xpos); 165 | string response = GetResponseString(xpos, challenge); 166 | int passTime = action.Get("passtime"); 167 | string actString = action.Get("action"); 168 | int imgLoadTime = rnd.Next(0, 200) + 50; 169 | Thread.Sleep(passTime - imgLoadTime); 170 | var ajaxUrl = string.Format("{0}ajax.php?gt={1}&challenge={2}&imgload={3}&passtime={4}&userresponse={5}&a={6}&callback=cb", 171 | config.Get("apiserver"), 172 | gt, 173 | challenge, 174 | imgLoadTime, 175 | passTime, 176 | response, 177 | actString 178 | ); 179 | 180 | var uri = new Uri(ajaxUrl); 181 | var hreq = (HttpWebRequest)HttpWebRequest.Create(uri); 182 | hreq.Timeout = 30000; 183 | hreq.Referer = referer; 184 | hreq.UserAgent = userAgent; 185 | hreq.CookieContainer = new CookieContainer(); 186 | 187 | hreq.CookieContainer.SetCookies(uri, cookies); 188 | var hres = (HttpWebResponse)hreq.GetResponse(); 189 | var js = ""; 190 | using (StreamReader sr = new StreamReader(hres.GetResponseStream())) 191 | js = sr.ReadToEnd(); 192 | hres.Close(); 193 | var json = js.Substring(3, js.Length - 4); 194 | //Console.WriteLine(json); 195 | var result = JsonObject.Parse(json); 196 | result["challenge"] = challenge; 197 | if (result.Get("success") == 1) 198 | { 199 | // success 200 | return result; 201 | } 202 | else if (result.Get("message") == "abuse") 203 | { 204 | // return abuse ,refresh config and try again 205 | return result; 206 | } 207 | else if (result.Get("message") == "forbidden") 208 | { 209 | // try next action 210 | } 211 | } 212 | // failed 213 | return null; 214 | } 215 | private List GetActions(int xpos) 216 | { 217 | var acts = new List(); 218 | 219 | for (var i = 0; i < 4; i++) 220 | { 221 | JsonObject act = new JsonObject(); 222 | act["pos"] = xpos.ToString(); 223 | var action = generate(xpos); 224 | act["action"] = encrypt(action); 225 | int pt = 0; 226 | foreach (var a in action) 227 | { 228 | pt += a[2]; 229 | } 230 | act["passtime"] = pt.ToString(); 231 | acts.Add(act); 232 | } 233 | return acts; 234 | 235 | } 236 | 237 | private List generate2(int xpos) 238 | { 239 | var sx = rnd.Next(15, 30); 240 | var sy = rnd.Next(15, 30); 241 | var arr = new List(); 242 | arr.Add(new int[] { sx, sy, 0 }); 243 | 244 | var maxCount = 100; // max len 100 245 | var mds = 0.25; 246 | var speed = rnd.NextDouble() * 0.3 + 0.05; 247 | var ds = rnd.NextDouble() * 0.5 * mds; 248 | var dsign = 1; 249 | double x = 0; 250 | double lx = xpos - x; 251 | while (Math.Abs(lx) > 1.0 && maxCount-- > 0) 252 | { 253 | var rn = rnd.NextDouble(); 254 | var dt = rn * 100 + 10; 255 | if (rn < 0.2) 256 | { 257 | dt += rn * 200; 258 | } 259 | 260 | speed += ds * dsign; 261 | if (speed > 0.25) 262 | speed = 0.25; 263 | rn = rnd.NextDouble(); 264 | 265 | if (rn < (speed / 0.25)) 266 | dsign = -dsign; 267 | ds = rnd.NextDouble() * mds * 0.5; 268 | if (Math.Abs(lx) < 10) 269 | { 270 | speed *= lx / 20; 271 | } 272 | else if (x < xpos / 3) 273 | { 274 | speed *= (x / xpos + 1.0); 275 | } 276 | 277 | if (speed < 0) 278 | speed = -speed; 279 | double dx = speed * dt; 280 | if (Math.Abs(dx) < 0.6) 281 | continue; 282 | 283 | x += dx; 284 | if (x - xpos > 0 && dx > 0) 285 | { 286 | speed = -speed; 287 | x -= 2 * dx; 288 | } 289 | 290 | rn = rnd.NextDouble(); 291 | double dy = 0; 292 | if (rn < 0.1 && dt > 70) 293 | { 294 | dy = rn * 30; 295 | if (rn < 0.05) 296 | dy = -rn * 60; 297 | } 298 | arr.Add(new int[] { (int)(dx + 0.5), (int)(dy + 0.5), (int)(dt + 0.5) }); 299 | lx = xpos - x; 300 | } 301 | var dtlast = 500.0 * rnd.NextDouble() + 100.0; 302 | arr.Add(new int[] { 0, 0, (int)(dtlast) }); 303 | return arr; 304 | } 305 | private List generate(int xpos) 306 | { 307 | var sx = rnd.Next(15, 30); 308 | var sy = rnd.Next(15, 30); 309 | var arr = new List(); 310 | arr.Add(new int[] { sx, sy, 0 }); 311 | var maxCount = 100; // max len 100 312 | double x = 0; 313 | double lx = xpos - x; 314 | while (Math.Abs(lx) > 0.8 && maxCount-- > 0) 315 | { 316 | var rn = rnd.NextDouble(); 317 | 318 | var dx = rn * lx * 0.6; 319 | if (Math.Abs(dx) < 0.5) 320 | continue; 321 | var dt = rnd.NextDouble() * (rn * 80 + 50)+ 10; 322 | 323 | rn = rnd.NextDouble(); 324 | double dy = 0; 325 | if (rn < 0.2 && dx > 10) // 326 | { 327 | dy = rn * 20.0; 328 | if (rn < 0.05) 329 | dy = -rn * 80; 330 | } 331 | 332 | x += dx; 333 | arr.Add(new int[] { (int)(dx + 0.5), (int)(dy + 0.5), (int)(dt + 0.5) }); 334 | lx = xpos - x; 335 | } 336 | var dtlast = 500.0 * rnd.NextDouble() + 100.0; 337 | arr.Add(new int[] { 0, 0, (int)(dtlast) }); 338 | return arr; 339 | } 340 | 341 | private List diff(List arr) 342 | { 343 | List b = new List(); 344 | for (var c = 0; c < arr.Count - 1; c++) 345 | { 346 | int[] e = new int[3]; 347 | e[0] = (arr[c + 1][0] - arr[c][0]); 348 | e[1] = (arr[c + 1][1] - arr[c][1]); 349 | e[2] = (arr[c + 1][2] - arr[c][2]); 350 | if (e[0] == 0 && e[1] == 0 && e[2] == 0) 351 | continue; 352 | b.Add(e); 353 | } 354 | return b; 355 | } 356 | private string encode(int n) 357 | { 358 | const string b = "()*,-./0123456789:?@ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqr"; 359 | var c = b.Length; 360 | char d = (char)0; 361 | var e = Math.Abs(n); 362 | var f = e / c; 363 | if (f >= c) 364 | f = c - 1; 365 | if (f != 0) 366 | { 367 | d = b[f]; 368 | e %= c; 369 | } 370 | var g = ""; 371 | if (n < 0) 372 | g += "!"; 373 | if (d != 0) 374 | g += "$"; 375 | 376 | return g + (d == 0 ? "": d.ToString()) + b[e]; 377 | } 378 | private char replace(int[] a2) 379 | { 380 | var b = new int[][] { new int[] { 1, 0 }, new int[] { 2, 0 }, new int[] { 1, -1 }, 381 | new int[] { 1, 1 }, new int[] { 0, 1 }, new int[] { 0, -1 }, 382 | new int[] { 3, 0 }, new int[] { 2, -1 }, new int[] { 2, 1 } }; 383 | var c = "stuvwxyz~"; 384 | for (var d = 0; d < b.Length; d++) 385 | if (a2[0] == b[d][0] && a2[1] == b[d][1]) 386 | return c[d]; 387 | return '\0'; 388 | } 389 | private string encrypt(List action) 390 | { 391 | var d = action;// diff(action); 392 | string dx = "", dy = "", dt = ""; 393 | for(var j=0; j 57) 419 | d[e] = f - 87; 420 | else 421 | d[e] = f - 48; 422 | } 423 | var c = 36 * d[0] + d[1]; 424 | var g = posx + c; 425 | ct = challenge.Substring(0, 32); 426 | var i = new List>(5); 427 | for(var ii =0; ii<5; ii++) 428 | { 429 | i.Add(new List()); 430 | } 431 | Dictionary j = new Dictionary(); 432 | int k = 0; 433 | foreach (var h in ct) 434 | { 435 | if (!j.Keys.Contains(h) || j[h] != 1) 436 | { 437 | j[h] = 1; 438 | i[k].Add(h); 439 | k++; 440 | k %= 5; 441 | } 442 | 443 | } 444 | int n = g, o = 4; 445 | var p = ""; 446 | var q = new int[] { 1, 2, 5, 10, 50 }.ToList(); ; 447 | Random rnd = new Random(); 448 | while (n > 0) 449 | { 450 | if (n - q[o] >= 0) 451 | { 452 | int m = rnd.Next(0, i[o].Count); 453 | p += i[o][m]; 454 | n -= q[o]; 455 | } 456 | else 457 | { 458 | i.RemoveAt(o); 459 | q.RemoveAt(o); 460 | o--; 461 | } 462 | } 463 | return p; 464 | } 465 | private Image LoadImage(string url) 466 | { 467 | Image image; 468 | HttpWebRequest hreq = (HttpWebRequest)HttpWebRequest.Create(url); 469 | HttpWebResponse hres = (HttpWebResponse)hreq.GetResponse(); 470 | using (var stream = hres.GetResponseStream()) 471 | { 472 | image = Image.FromStream(stream); 473 | } 474 | hres.Close(); 475 | return image; 476 | } 477 | private Image AlignImage(Image img, int ypos = 0, int height = 52) 478 | { 479 | const int width = 260; 480 | Bitmap bmp = new Bitmap(width, height); 481 | var pos = new int[] {157, 145, 265, 277,181, 169, 241, 253, 109, 97, 289, 301, 85, 73, 25, 37, 13, 1, 121, 133, 61, 49, 217, 229, 205, 193, 482 | 145, 157, 277, 265, 169, 181, 253, 241, 97, 109, 301, 289, 73, 85, 37, 25, 1, 13, 133, 121, 49, 61, 229, 217, 193, 205}; 483 | int dx = 0, sy = 58, dy = 0; 484 | var g = Graphics.FromImage(bmp); 485 | for (var i = 0; i < pos.Length; i++) { 486 | g.DrawImage(img, new Rectangle(dx, dy - ypos, 10, 58), new Rectangle(pos[i], sy, 10, 58), GraphicsUnit.Pixel); 487 | dx += 10; 488 | if (dx == width) 489 | { 490 | dx = 0; 491 | dy = 58; 492 | sy = 0; 493 | } 494 | } 495 | g.Dispose(); 496 | return bmp; 497 | } 498 | private int GetPositionX(Image imgBg, Image imgFullBg, Image imgSlice = null) 499 | { 500 | var bg = new Bitmap(imgBg); 501 | var full = new Bitmap(imgFullBg); 502 | Rectangle rect = new Rectangle(0, 0, bg.Width, bg.Height); 503 | const int bytesCount = 4; 504 | var bgData = bg.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); 505 | var fullData = full.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); 506 | int xpos = -1; 507 | unsafe 508 | { 509 | byte * pBg =(byte *)bgData.Scan0; 510 | byte * pFull = (byte *)fullData.Scan0; 511 | //sub 2 images 512 | for (var i = 0; i < bgData.Stride * bgData.Height; i+=4) 513 | { 514 | pBg[i] = (byte)Math.Abs((int)pBg[i] - pFull[i]); 515 | pBg[i + 1] = (byte)Math.Abs((int)pBg[i + 1] - pFull[i + 1]); 516 | pBg[i + 2] = (byte)Math.Abs((int)pBg[i + 2] - pFull[i + 2]); 517 | } 518 | var w = bgData.Width; 519 | // Roberts edge detect and calculate histgram 520 | int[] histgram = new int[w]; 521 | int[] histSum = new int[w]; 522 | for (var y = 0; y < bgData.Height - 1; y++) 523 | { 524 | for (var x = 0; x < w - 1; x++) 525 | { 526 | var i00 = (x + y * w); 527 | var i11 = (i00 + w + 1) * bytesCount; 528 | var i01 = (i00 + 1) * bytesCount; 529 | var i10 = (i00 + w) * bytesCount; 530 | i00 *= bytesCount; 531 | pFull[i00] = (byte)(Math.Abs(pBg[i00] - pBg[i11]) + Math.Abs(pBg[i01] - pBg[i10])); // b 532 | pFull[i00 + 1] = (byte)(Math.Abs(pBg[i00 + 1] - pBg[i11 + 1]) + Math.Abs(pBg[i01 + 1] - pBg[i10 + 1])); // g 533 | pFull[i00 + 2] = (byte)(Math.Abs(pBg[i00 + 2] - pBg[i11 + 2]) + Math.Abs(pBg[i01 + 2] - pBg[i10 + 2])); // r 534 | histgram[x] += pFull[i00] + pFull[i00 + 1] + pFull[i00 + 2]; 535 | } 536 | } 537 | // find xpos 538 | int ww = 48, maxValue = -1; 539 | for (var i = 0; i < ww; i++) 540 | histSum[0] += histgram[i]; 541 | for (var x = 1; x < w - ww; x++) 542 | { 543 | histSum[x] = histSum[x - 1] + histgram[x + ww - 1] - histgram[x - 1]; 544 | if (histSum[x] > maxValue) 545 | { 546 | xpos = x; 547 | maxValue = histSum[x]; 548 | } 549 | } 550 | } // exit unsafe 551 | bg.UnlockBits(bgData); 552 | full.UnlockBits(fullData); 553 | //offset 6 pixels 554 | return xpos - 6; 555 | } 556 | } 557 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Try to crack geetest in CSharp 2 | ## dependencies: ## 3 | + [ ServiceStack.Text](https://github.com/ServiceStack/ServiceStack.Text) - [install](https://www.nuget.org/packages/ServiceStack.Text/) 4 | 5 | ## usage: ## 6 |

 7 |             var gk = new Geek([gt], [site]);
 8 |             var jsonObj = gk.GetValidate();
 9 |             if (jsonObj != null)
10 |                 Console.WriteLine(jsonObj["validate"]);
11 |             else
12 |                 Console.WriteLine("*** failed ***");
13 | 
14 | 15 | ## demo: ## 16 | + [online test](http://wsguest.iok.la:14872/gee/test.aspx) 17 | + [online test2](http://wsguest.iok.la:14872/gee/test2.aspx) 18 | + [demo.gif](/demo/geetest.gif) 19 | 20 | ## contact: ## 21 | + 1595152095@qq.com -------------------------------------------------------------------------------- /demo/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /demo/Geek.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Collections.Generic; 4 | using System.Drawing; 5 | using System.Drawing.Imaging; 6 | using System.IO; 7 | using System.Net; 8 | using System.Threading; 9 | using ServiceStack.Text; 10 | namespace GeetestCrack 11 | { 12 | public class Geek 13 | { 14 | private JsonObject config = null; 15 | private string referer = ""; 16 | private string userAgent = "[your user agent]"; 17 | Random rnd = new Random(); 18 | public string challenge 19 | { 20 | get 21 | { 22 | if (config != null) 23 | return config.Get("challenge"); 24 | else 25 | return ""; 26 | } 27 | private set 28 | { 29 | if (config == null) 30 | config = new JsonObject(); 31 | config["challenge"] = value; 32 | } 33 | } 34 | public string gt 35 | { 36 | get 37 | { 38 | if (config != null) 39 | return config.Get("gt"); 40 | else 41 | return ""; 42 | } 43 | set 44 | { 45 | if (config == null) 46 | config = new JsonObject(); 47 | config["gt"] = value; 48 | } 49 | } 50 | public Geek(string gt = "", string referer = "") 51 | { 52 | if (!string.IsNullOrEmpty(gt)) 53 | this.gt = gt; 54 | if(!string.IsNullOrEmpty(referer)) 55 | this.referer = referer; 56 | GetConfig(); 57 | } 58 | public Geek(Uri uri) 59 | { 60 | string source = ""; 61 | HttpWebRequest hreq = (HttpWebRequest)HttpWebRequest.Create(uri); 62 | HttpWebResponse hres = (HttpWebResponse)hreq.GetResponse(); 63 | using (StreamReader sr = new StreamReader(hres.GetResponseStream())) 64 | source = sr.ReadToEnd(); 65 | hres.Close(); 66 | var obj = JsonObject.Parse(source); 67 | this.gt = obj.Get("gt"); 68 | this.referer = uri.Host; 69 | challenge = obj.Get("challenge"); 70 | GetConfig(); 71 | } 72 | 73 | public void GetConfig() 74 | { 75 | if (string.IsNullOrEmpty(gt)) 76 | return; 77 | var getUrl = string.Format("http://api.geetest.com/get.php?gt={0}&challenge={1}&product=embed&offline=false", gt, challenge); 78 | Uri uri = new Uri(getUrl); 79 | HttpWebRequest hreq = (HttpWebRequest)HttpWebRequest.Create(uri); 80 | hreq.Timeout = 10000; 81 | hreq.Referer = this.referer; 82 | hreq.CookieContainer = new CookieContainer(); 83 | HttpWebResponse hres = (HttpWebResponse)hreq.GetResponse(); 84 | var cookies = hreq.CookieContainer.GetCookieHeader(uri); 85 | string js = ""; 86 | using (StreamReader sr = new StreamReader(hres.GetResponseStream())) 87 | js = sr.ReadToEnd(); 88 | hres.Close(); 89 | 90 | var sIndex = js.IndexOf("new Geetest({"); 91 | if (sIndex < 1) 92 | return; 93 | var eIndex = js.IndexOf("},true)", sIndex); 94 | if (eIndex < sIndex) 95 | return; 96 | var json = js.Substring(sIndex + 12, eIndex - sIndex - 11); 97 | 98 | config = JsonObject.Parse(json); 99 | config["cookie"] = cookies; 100 | config["initchallenge"] = config["challenge"]; 101 | //Console.WriteLine("config: " + config.Dump()); 102 | } 103 | 104 | public bool RefreshConfig() 105 | { 106 | if (string.IsNullOrEmpty(gt)) 107 | return false; 108 | var refreshUrl = string.Format("http://api.geetest.com/refresh.php?gt={0}&challenge={1}&callback=cb", gt, challenge); 109 | Uri uri = new Uri(refreshUrl); 110 | string js = ""; 111 | try 112 | { 113 | HttpWebRequest hreq = (HttpWebRequest)HttpWebRequest.Create(uri); 114 | hreq.Timeout = 10000; 115 | hreq.Referer = this.referer; 116 | hreq.CookieContainer = new CookieContainer(); 117 | var cookies = config.Get("cookie"); 118 | hreq.CookieContainer.SetCookies(uri, cookies); 119 | HttpWebResponse hres = (HttpWebResponse)hreq.GetResponse(); 120 | using (StreamReader sr = new StreamReader(hres.GetResponseStream())) 121 | js = sr.ReadToEnd(); 122 | hres.Close(); 123 | } 124 | catch(Exception ex) 125 | { 126 | //Console.WriteLine("refresh error: " + ex.Message); 127 | challenge = config["initchallenge"]; 128 | } 129 | 130 | if (string.IsNullOrEmpty(js)) 131 | return false; 132 | var json = js.Substring(3, js.Length - 4); 133 | 134 | var newParams = JsonObject.Parse(json); 135 | config["ypos"] = newParams["ypos"]; 136 | config["challenge"] = newParams["challenge"]; 137 | config["bg"] = newParams["bg"]; 138 | config["fullbg"] = newParams["fullbg"]; 139 | config["slice"] = newParams["slice"]; 140 | //Console.WriteLine("config refreshed: " + config.Dump()); 141 | return true; 142 | } 143 | 144 | public JsonObject GetValidate() 145 | { 146 | // load images 147 | var imgUrlBase = string.Format("http://{0}", config.Get("staticservers")[0]); 148 | Image bg = LoadImage(imgUrlBase + config.Get("bg")); 149 | Image full = LoadImage(imgUrlBase + config.Get("fullbg")); 150 | int ypos = config.Get("ypos") + 3; 151 | bg = AlignImage(bg, ypos); 152 | full = AlignImage(full, ypos); 153 | 154 | // get position 155 | int xpos = GetPositionX(bg, full); 156 | config["xpos"] = xpos.ToString(); 157 | var actions = GetActions(xpos); 158 | //Console.WriteLine("xpos: " + xpos); 159 | // try actions 160 | var cookies = config.Get("cookie"); 161 | foreach(var action in actions) 162 | { 163 | xpos = action.Get("pos"); 164 | //Console.WriteLine("try pos: " + xpos); 165 | string response = GetResponseString(xpos, challenge); 166 | int passTime = action.Get("passtime"); 167 | string actString = action.Get("action"); 168 | int imgLoadTime = rnd.Next(0, 200) + 50; 169 | 170 | var ajaxUrl = string.Format("{0}ajax.php?gt={1}&challenge={2}&imgload={3}&passtime={4}&userresponse={5}&a={6}&callback=cb", 171 | config.Get("apiserver"), 172 | gt, 173 | challenge, 174 | imgLoadTime, 175 | passTime, 176 | response, 177 | actString 178 | ); 179 | 180 | var uri = new Uri(ajaxUrl); 181 | var hreq = (HttpWebRequest)HttpWebRequest.Create(uri); 182 | hreq.Timeout = 30000; 183 | hreq.Referer = referer; 184 | hreq.UserAgent = userAgent; 185 | hreq.CookieContainer = new CookieContainer(); 186 | 187 | hreq.CookieContainer.SetCookies(uri, cookies); 188 | var hres = (HttpWebResponse)hreq.GetResponse(); 189 | var js = ""; 190 | using (StreamReader sr = new StreamReader(hres.GetResponseStream())) 191 | js = sr.ReadToEnd(); 192 | hres.Close(); 193 | var json = js.Substring(3, js.Length - 4); 194 | //Console.WriteLine(json); 195 | var result = JsonObject.Parse(json); 196 | result["challenge"] = challenge; 197 | if (result.Get("success") == 1) 198 | { 199 | // success 200 | return result; 201 | } 202 | else if (result.Get("message") == "abuse") 203 | { 204 | // return abuse ,refresh config and try again 205 | return result; 206 | } 207 | else if (result.Get("message") == "forbidden") 208 | { 209 | // try next action 210 | } 211 | } 212 | // failed 213 | return null; 214 | } 215 | private List GetActions(int xpos) 216 | { 217 | var acts = new List(); 218 | 219 | for (var i = 0; i < 4; i++) 220 | { 221 | JsonObject act = new JsonObject(); 222 | act["pos"] = xpos.ToString(); 223 | var action = generate(xpos); 224 | act["action"] = encrypt(action); 225 | int pt = 0; 226 | foreach (var a in action) 227 | { 228 | pt += a[2]; 229 | } 230 | act["passtime"] = pt.ToString(); 231 | acts.Add(act); 232 | } 233 | return acts; 234 | 235 | } 236 | 237 | private List generate(int xpos) 238 | { 239 | var sx = rnd.Next(15, 30); 240 | var sy = rnd.Next(15, 30); 241 | var arr = new List(); 242 | arr.Add(new int[] { sx, sy, 0 }); 243 | var maxCount = 100; // max len 100 244 | double x = 0; 245 | double lx = xpos - x; 246 | while (Math.Abs(lx) > 0.8 && maxCount-- > 0) 247 | { 248 | var rn = rnd.NextDouble(); 249 | 250 | var dx = rn * lx * 0.6; 251 | if (Math.Abs(dx) < 0.5) 252 | continue; 253 | var dt = rnd.NextDouble() * (rn * 80 + 50)+ 10; 254 | 255 | rn = rnd.NextDouble(); 256 | double dy = 0; 257 | if (rn < 0.2 && dx > 10) // 258 | { 259 | dy = rn * 20.0; 260 | if (rn < 0.05) 261 | dy = -rn * 80; 262 | } 263 | 264 | x += dx; 265 | arr.Add(new int[] { (int)(dx + 0.5), (int)(dy + 0.5), (int)(dt + 0.5) }); 266 | lx = xpos - x; 267 | } 268 | var dtlast = 500.0 * rnd.NextDouble() + 100.0; 269 | arr.Add(new int[] { 0, 0, (int)(dtlast) }); 270 | return arr; 271 | } 272 | 273 | private List diff(List arr) 274 | { 275 | List b = new List(); 276 | for (var c = 0; c < arr.Count - 1; c++) 277 | { 278 | int[] e = new int[3]; 279 | e[0] = (arr[c + 1][0] - arr[c][0]); 280 | e[1] = (arr[c + 1][1] - arr[c][1]); 281 | e[2] = (arr[c + 1][2] - arr[c][2]); 282 | if (e[0] == 0 && e[1] == 0 && e[2] == 0) 283 | continue; 284 | b.Add(e); 285 | } 286 | return b; 287 | } 288 | private string encode(int n) 289 | { 290 | const string b = "()*,-./0123456789:?@ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqr"; 291 | var c = b.Length; 292 | char d = (char)0; 293 | var e = Math.Abs(n); 294 | var f = e / c; 295 | if (f >= c) 296 | f = c - 1; 297 | if (f != 0) 298 | { 299 | d = b[f]; 300 | e %= c; 301 | } 302 | var g = ""; 303 | if (n < 0) 304 | g += "!"; 305 | if (d != 0) 306 | g += "$"; 307 | 308 | return g + (d == 0 ? "": d.ToString()) + b[e]; 309 | } 310 | private char replace(int[] a2) 311 | { 312 | var b = new int[][] { new int[] { 1, 0 }, new int[] { 2, 0 }, new int[] { 1, -1 }, 313 | new int[] { 1, 1 }, new int[] { 0, 1 }, new int[] { 0, -1 }, 314 | new int[] { 3, 0 }, new int[] { 2, -1 }, new int[] { 2, 1 } }; 315 | var c = "stuvwxyz~"; 316 | for (var d = 0; d < b.Length; d++) 317 | if (a2[0] == b[d][0] && a2[1] == b[d][1]) 318 | return c[d]; 319 | return '\0'; 320 | } 321 | private string encrypt(List action) 322 | { 323 | var d = action;// diff(action); 324 | string dx = "", dy = "", dt = ""; 325 | for(var j=0; j 57) 351 | d[e] = f - 87; 352 | else 353 | d[e] = f - 48; 354 | } 355 | var c = 36 * d[0] + d[1]; 356 | var g = posx + c; 357 | ct = challenge.Substring(0, 32); 358 | var i = new List>(5); 359 | for(var ii =0; ii<5; ii++) 360 | { 361 | i.Add(new List()); 362 | } 363 | Dictionary j = new Dictionary(); 364 | int k = 0; 365 | foreach (var h in ct) 366 | { 367 | if (!j.Keys.Contains(h) || j[h] != 1) 368 | { 369 | j[h] = 1; 370 | i[k].Add(h); 371 | k++; 372 | k %= 5; 373 | } 374 | 375 | } 376 | int n = g, o = 4; 377 | var p = ""; 378 | var q = new int[] { 1, 2, 5, 10, 50 }.ToList(); ; 379 | Random rnd = new Random(); 380 | while (n > 0) 381 | { 382 | if (n - q[o] >= 0) 383 | { 384 | int m = rnd.Next(0, i[o].Count); 385 | p += i[o][m]; 386 | n -= q[o]; 387 | } 388 | else 389 | { 390 | i.RemoveAt(o); 391 | q.RemoveAt(o); 392 | o--; 393 | } 394 | } 395 | return p; 396 | } 397 | private Image LoadImage(string url) 398 | { 399 | Image image; 400 | HttpWebRequest hreq = (HttpWebRequest)HttpWebRequest.Create(url); 401 | HttpWebResponse hres = (HttpWebResponse)hreq.GetResponse(); 402 | using (var stream = hres.GetResponseStream()) 403 | { 404 | image = Image.FromStream(stream); 405 | } 406 | hres.Close(); 407 | return image; 408 | } 409 | private Image AlignImage(Image img, int ypos = 0, int height = 52) 410 | { 411 | const int width = 260; 412 | Bitmap bmp = new Bitmap(width, height); 413 | var pos = new int[] {157, 145, 265, 277,181, 169, 241, 253, 109, 97, 289, 301, 85, 73, 25, 37, 13, 1, 121, 133, 61, 49, 217, 229, 205, 193, 414 | 145, 157, 277, 265, 169, 181, 253, 241, 97, 109, 301, 289, 73, 85, 37, 25, 1, 13, 133, 121, 49, 61, 229, 217, 193, 205}; 415 | int dx = 0, sy = 58, dy = 0; 416 | var g = Graphics.FromImage(bmp); 417 | for (var i = 0; i < pos.Length; i++) { 418 | g.DrawImage(img, new Rectangle(dx, dy - ypos, 10, 58), new Rectangle(pos[i], sy, 10, 58), GraphicsUnit.Pixel); 419 | dx += 10; 420 | if (dx == width) 421 | { 422 | dx = 0; 423 | dy = 58; 424 | sy = 0; 425 | } 426 | } 427 | g.Dispose(); 428 | return bmp; 429 | } 430 | private int GetPositionX(Image imgBg, Image imgFullBg, Image imgSlice = null) 431 | { 432 | var bg = new Bitmap(imgBg); 433 | var full = new Bitmap(imgFullBg); 434 | Rectangle rect = new Rectangle(0, 0, bg.Width, bg.Height); 435 | const int bytesCount = 4; 436 | var bgData = bg.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); 437 | var fullData = full.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); 438 | int xpos = -1; 439 | unsafe 440 | { 441 | byte * pBg =(byte *)bgData.Scan0; 442 | byte * pFull = (byte *)fullData.Scan0; 443 | //sub 2 images 444 | for (var i = 0; i < bgData.Stride * bgData.Height; i+=4) 445 | { 446 | pBg[i] = (byte)Math.Abs((int)pBg[i] - pFull[i]); 447 | pBg[i + 1] = (byte)Math.Abs((int)pBg[i + 1] - pFull[i + 1]); 448 | pBg[i + 2] = (byte)Math.Abs((int)pBg[i + 2] - pFull[i + 2]); 449 | } 450 | var w = bgData.Width; 451 | // Roberts edge detect and calculate histgram 452 | int[] histgram = new int[w]; 453 | int[] histSum = new int[w]; 454 | for (var y = 0; y < bgData.Height - 1; y++) 455 | { 456 | for (var x = 0; x < w - 1; x++) 457 | { 458 | var i00 = (x + y * w); 459 | var i11 = (i00 + w + 1) * bytesCount; 460 | var i01 = (i00 + 1) * bytesCount; 461 | var i10 = (i00 + w) * bytesCount; 462 | i00 *= bytesCount; 463 | pFull[i00] = (byte)(Math.Abs(pBg[i00] - pBg[i11]) + Math.Abs(pBg[i01] - pBg[i10])); // b 464 | pFull[i00 + 1] = (byte)(Math.Abs(pBg[i00 + 1] - pBg[i11 + 1]) + Math.Abs(pBg[i01 + 1] - pBg[i10 + 1])); // g 465 | pFull[i00 + 2] = (byte)(Math.Abs(pBg[i00 + 2] - pBg[i11 + 2]) + Math.Abs(pBg[i01 + 2] - pBg[i10 + 2])); // r 466 | histgram[x] += pFull[i00] + pFull[i00 + 1] + pFull[i00 + 2]; 467 | } 468 | } 469 | // find xpos 470 | int ww = 48, maxValue = -1; 471 | for (var i = 0; i < ww; i++) 472 | histSum[0] += histgram[i]; 473 | for (var x = 1; x < w - ww; x++) 474 | { 475 | histSum[x] = histSum[x - 1] + histgram[x + ww - 1] - histgram[x - 1]; 476 | if (histSum[x] > maxValue) 477 | { 478 | xpos = x; 479 | maxValue = histSum[x]; 480 | } 481 | } 482 | } // exit unsafe 483 | bg.UnlockBits(bgData); 484 | full.UnlockBits(fullData); 485 | //offset 6 pixels 486 | return xpos - 6; 487 | } 488 | } 489 | } 490 | -------------------------------------------------------------------------------- /demo/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using GeetestCrack; 7 | namespace demo 8 | { 9 | class Program 10 | { 11 | static void Main(string[] args) 12 | { 13 | var gk = new Geek("421b84eeaee7b2aed4c0ec5706d8b571", "http://www.geetest.com/"); 14 | var jsonObj = gk.GetValidate(); 15 | if (jsonObj != null) 16 | Console.WriteLine(jsonObj["validate"]); 17 | else 18 | Console.WriteLine("*** failed ***"); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /demo/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 有关程序集的常规信息通过以下 6 | // 特性集控制。更改这些特性值可修改 7 | // 与程序集关联的信息。 8 | [assembly: AssemblyTitle("demo")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("demo")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // 将 ComVisible 设置为 false 使此程序集中的类型 18 | // 对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型, 19 | // 则将该类型上的 ComVisible 特性设置为 true。 20 | [assembly: ComVisible(false)] 21 | 22 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID 23 | [assembly: Guid("6dd61a0a-34ff-4bcc-aaee-80e6078134a4")] 24 | 25 | // 程序集的版本信息由下面四个值组成: 26 | // 27 | // 主版本 28 | // 次版本 29 | // 生成号 30 | // 修订号 31 | // 32 | // 可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值, 33 | // 方法是按如下所示使用“*”: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /demo/demo.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {1701446D-BA9F-4FD5-A83E-873565D0373F} 8 | Exe 9 | Properties 10 | demo 11 | demo 12 | v4.5.1 13 | 512 14 | true 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | true 26 | 27 | 28 | AnyCPU 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | 36 | 37 | 38 | packages\ServiceStack.Text.4.0.60\lib\net40\ServiceStack.Text.dll 39 | True 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 67 | -------------------------------------------------------------------------------- /demo/demo.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.40629.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "demo", "demo.csproj", "{1701446D-BA9F-4FD5-A83E-873565D0373F}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {1701446D-BA9F-4FD5-A83E-873565D0373F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {1701446D-BA9F-4FD5-A83E-873565D0373F}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {1701446D-BA9F-4FD5-A83E-873565D0373F}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {1701446D-BA9F-4FD5-A83E-873565D0373F}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /demo/geetest.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wsguest/geetest/d248bce63ebc084af225a30c1dc2247ae989adb4/demo/geetest.gif --------------------------------------------------------------------------------