struct r_bin_pe_addr_t *PE_(check_msvcseh)(RBinPEObj *pe) {
	r_return_val_if_fail (pe && pe->b, NULL);
	ut8 b[512];
	size_t n = 0;
	struct r_bin_pe_addr_t* entry = PE_(r_bin_pe_get_entrypoint) (pe);
	ZERO_FILL (b);
	if (r_buf_read_at (pe->b, entry->paddr, b, sizeof (b)) < 0) {
		pe_printf ("Warning: Cannot read entry at 0x%08"PFMT64x "\n", entry->paddr);
		free (entry);
		return NULL;
	}

	read_and_follow_jump (entry, pe->b, b, sizeof (b), pe->big_endian);

	// MSVC SEH
	// E8 13 09 00 00  call    0x44C388
	// E9 05 00 00 00  jmp     0x44BA7F
	if (b[0] == 0xe8 && b[5] == 0xe9) {
		if (follow_offset (entry, pe->b, b, sizeof (b), pe->big_endian, 5)) {
			// case1:
			// from des address of jmp search for 68 xx xx xx xx e8 and test xx xx xx xx = imagebase
			// 68 00 00 40 00  push    0x400000
			// E8 3E F9 FF FF  call    0x44B4FF
			ut32 imageBase = pe->nt_headers->optional_header.ImageBase;
			for (n = 0; n < sizeof (b) - 6; n++) {
				const ut32 tmp_imgbase = r_read_ble32 (b + n + 1, pe->big_endian);
				if (b[n] == 0x68 && tmp_imgbase == imageBase && b[n + 5] == 0xe8) {
					follow_offset (entry, pe->b, b, sizeof (b), pe->big_endian, n + 5);
					return entry;
				}
			}
			//case2:
			// from des address of jmp search for 50 FF xx FF xx E8
			//50			 push    eax
			//FF 37			 push    dword ptr[edi]
			//FF 36          push    dword ptr[esi]
			//E8 6F FC FF FF call    _main
			for (n = 0; n < sizeof (b) - 6; n++) {
				if (b[n] == 0x50 && b[n+1] == 0xff && b[n + 3] == 0xff && b[n + 5] == 0xe8) {
					follow_offset (entry, pe->b, b, sizeof (b), pe->big_endian, n + 5);
					return entry;
				}
			}
			//case3:
			//50                                         push    eax
			//FF 35 0C E2 40 00                          push    xxxxxxxx
			//FF 35 08 E2 40 00                          push    xxxxxxxx
			//E8 2B FD FF FF                             call    _main
			for (n = 0; n < sizeof (b) - 20; n++) {
				if (b[n] == 0x50 && b[n + 1] == 0xff && b[n + 7] == 0xff && b[n + 13] == 0xe8) {
					follow_offset (entry, pe->b, b, sizeof (b), pe->big_endian, n + 13);
					return entry;
				}
			}
			//case4:
			//50                                        push    eax
			//57                                        push    edi
			//FF 36                                     push    dword ptr[esi]
			//E8 D9 FD FF FF                            call    _main
			for (n = 0; n < sizeof (b) - 5; n++) {
				if (b[n] == 0x50 && b[n + 1] == 0x57 && b[n + 2] == 0xff && b[n + 4] == 0xe8) {
					follow_offset (entry, pe->b, b, sizeof (b), pe->big_endian, n + 4);
					return entry;
				}
			}
			//case5:
			//57                                        push    edi
			//56                                        push    esi
			//FF 36                                     push    dword ptr[eax]
			//E8 D9 FD FF FF                            call    _main
			for (n = 0; n < sizeof (b) - 5; n++) {
				if (b[n] == 0x57 && b[n + 1] == 0x56 && b[n + 2] == 0xff && b[n + 4] == 0xe8) {
					follow_offset (entry, pe->b, b, sizeof (b), pe->big_endian, n + 4);
					return entry;
				}
			}
		}
	}

	// MSVC 32bit debug
	if (b[3] == 0xe8) {
		// 55                    push ebp
		// 8B EC                 mov ebp, esp
		// E8 xx xx xx xx        call xxxxxxxx
		// 5D                    pop ebp
		// C3                    ret
		follow_offset (entry, pe->b, b, sizeof (b), pe->big_endian, 3);
		if (b[8] == 0xe8) {
			// 55                    push ebp
			// 8B EC                 mov ebp, esp
			// E8 xx xx xx xx        call xxxxxxxx
			// E8 xx xx xx xx        call xxxxxxxx <- Follow this
			// 5D                    pop ebp
			// C3                    ret
			follow_offset (entry, pe->b, b, sizeof (b), pe->big_endian, 8);
			for (n = 0; n + 16 < sizeof (b); n++) {
				// E8 xx xx xx xx    call sub.ucrtbased.dll__register_thread_local_exe_atexit_callback
				// 83 C4 04          add esp, 4
				// E8 xx xx xx xx    call xxxxxxxx <- Follow this
				// 89 xx xx          mov dword [xxxx], eax
				// E8 xx xx xx xx    call xxxxxxxx
				if (b[n] == 0xe8 && n + 8 <= sizeof (b) && !memcmp (b + n + 5, "\x83\xc4\x04", 3)
					&& b[n + 8] == 0xe8 && b[n + 13] == 0x89 && b[n + 16] == 0xe8) {
					follow_offset (entry, pe->b, b, sizeof (b), pe->big_endian, n + 8);
					int j, calls = 0;
					for (j = 0; j < sizeof (b) - 4; j++) {
						if (b[j] == 0xe8) {
							// E8 xx xx xx xx        call xxxxxxxx
							calls++;
							if (calls == 4) {
								follow_offset (entry, pe->b, b, sizeof (b), pe->big_endian, j);
								return entry;
							}
						}
					}
				}
			}
		}
	}

	// MSVC AMD64
	if (b[4] == 0xe8) {
		bool found_caller = false;
		if (b[13] == 0xe9) {
			// 48 83 EC 28       sub     rsp, 0x28
			// E8 xx xx xx xx    call    xxxxxxxx
			// 48 83 C4 28       add     rsp, 0x28
			// E9 xx xx xx xx    jmp     xxxxxxxx <- Follow this
			found_caller = follow_offset (entry, pe->b, b, sizeof (b), pe->big_endian, 13);
		} else {
			// Debug
			// 48 83 EC 28       sub     rsp, 0x28
			// E8 xx xx xx xx    call    xxxxxxxx
			// 48 83 C4 28       add     rsp, 0x28
			// C3                ret
			follow_offset (entry, pe->b, b, sizeof (b), pe->big_endian, 4);
			if (b[9] == 0xe8) {
				// 48 83 EC 28       sub     rsp, 0x28
				// E8 xx xx xx xx    call    xxxxxxxx
				// E8 xx xx xx xx    call    xxxxxxxx <- Follow this
				// 48 83 C4 28       add     rsp, 0x28
				// C3                ret
				follow_offset (entry, pe->b, b, sizeof (b), pe->big_endian, 9);
				if (b[0x129] == 0xe8) {
					// E8 xx xx xx xx        call xxxxxxxx
					found_caller = follow_offset (entry, pe->b, b, sizeof (b), pe->big_endian, 0x129);
				}
			}
		}
		if (found_caller) {
			// from des address of jmp, search for 4C ... 48 ... 8B ... E8
			// 4C 8B C0                    mov     r8, rax
			// 48 8B 17                    mov     rdx, qword [rdi]
			// 8B 0B                       mov     ecx, dword [rbx]
			// E8 xx xx xx xx              call    main
			// or
			// 4C 8B 44 24 28              mov r8, qword [rsp + 0x28]
			// 48 8B 54 24 30              mov rdx, qword [rsp + 0x30]
			// 8B 4C 24 20                 mov ecx, dword [rsp + 0x20]
			// E8 xx xx xx xx              call    main
			for (n = 0; n + 14 < sizeof (b); n++) {
				if (b[n] == 0x4c && b[n + 3] == 0x48 && b[n + 6] == 0x8b && b[n + 8] == 0xe8) {
					follow_offset (entry, pe->b, b, sizeof (b), pe->big_endian, n + 8);
					return entry;
				}
				if (b[n] == 0x4c && b [n + 5] == 0x48 && b[n + 10] == 0x8b && b[n + 14] == 0xe8) {
					follow_offset (entry, pe->b, b, sizeof (b), pe->big_endian, n + 14);
					return entry;
				}
			}
		}
	}
	//Microsoft Visual-C
	// 50                  push eax
	// FF 75 9C            push dword [ebp - local_64h]
	// 56                  push    esi
	// 56                  push    esi
	// FF 15 CC C0  44 00  call dword [sym.imp.KERNEL32.dll_GetModuleHandleA]
	// 50                  push    eax
	// E8 DB DA 00 00      call    main
	// 89 45 A0            mov dword [ebp - local_60h], eax
	// 50                  push    eax
	// E8 2D 00 00  00     call 0x4015a6
	if (b[188] == 0x50 && b[201] == 0xe8) {
		follow_offset (entry, pe->b, b, sizeof (b), pe->big_endian, 201);
		return entry;
	}

	if (b[292] == 0x50 && b[303] == 0xe8) {
		follow_offset (entry, pe->b, b, sizeof (b), pe->big_endian, 303);
		return entry;
	}

	free (entry);
	return NULL;
}
struct r_bin_pe_addr_t *PE_(check_msvcseh)(RBinPEObj *pe) {
	r_return_val_if_fail (pe && pe->b, NULL);
	ut8 b[512];
	size_t n = 0;
	struct r_bin_pe_addr_t* entry = PE_(r_bin_pe_get_entrypoint) (pe);
	ZERO_FILL (b);
	if (r_buf_read_at (pe->b, entry->paddr, b, sizeof (b)) < 0) {
		pe_printf ("Warning: Cannot read entry at 0x%08"PFMT64x "\n", entry->paddr);
		free (entry);
		return NULL;
	}

	read_and_follow_jump (entry, pe->b, b, sizeof (b), pe->big_endian);

	 
	 
	 
	if (b[0] == 0xe8 && b[5] == 0xe9) {
		if (follow_offset (entry, pe->b, b, sizeof (b), pe->big_endian, 5)) {
			 
			 
			 
			 
			ut32 imageBase = pe->nt_headers->optional_header.ImageBase;
			for (n = 0; n < sizeof (b) - 6; n++) {
				const ut32 tmp_imgbase = r_read_ble32 (b + n + 1, pe->big_endian);
				if (b[n] == 0x68 && tmp_imgbase == imageBase && b[n + 5] == 0xe8) {
					follow_offset (entry, pe->b, b, sizeof (b), pe->big_endian, n + 5);
					return entry;
				}
			}
			 
			 
			 
			 
			 
			 
			for (n = 0; n < sizeof (b) - 6; n++) {
				if (b[n] == 0x50 && b[n+1] == 0xff && b[n + 3] == 0xff && b[n + 5] == 0xe8) {
					follow_offset (entry, pe->b, b, sizeof (b), pe->big_endian, n + 5);
					return entry;
				}
			}
			 
			 
			 
			 
			 
			for (n = 0; n < sizeof (b) - 20; n++) {
				if (b[n] == 0x50 && b[n + 1] == 0xff && b[n + 7] == 0xff && b[n + 13] == 0xe8) {
					follow_offset (entry, pe->b, b, sizeof (b), pe->big_endian, n + 13);
					return entry;
				}
			}
			 
			 
			 
			 
			 
			for (n = 0; n < sizeof (b) - 5; n++) {
				if (b[n] == 0x50 && b[n + 1] == 0x57 && b[n + 2] == 0xff && b[n + 4] == 0xe8) {
					follow_offset (entry, pe->b, b, sizeof (b), pe->big_endian, n + 4);
					return entry;
				}
			}
			 
			 
			 
			 
			 
			for (n = 0; n < sizeof (b) - 5; n++) {
				if (b[n] == 0x57 && b[n + 1] == 0x56 && b[n + 2] == 0xff && b[n + 4] == 0xe8) {
					follow_offset (entry, pe->b, b, sizeof (b), pe->big_endian, n + 4);
					return entry;
				}
			}
		}
	}

	 
	if (b[3] == 0xe8) {
		 
		 
		 
		 
		 
		follow_offset (entry, pe->b, b, sizeof (b), pe->big_endian, 3);
		if (b[8] == 0xe8) {
			 
			 
			 
			 
			 
			 
			follow_offset (entry, pe->b, b, sizeof (b), pe->big_endian, 8);
			for (n = 0; n + 16 < sizeof (b); n++) {
				 
				 
				 
				 
				 
				if (b[n] == 0xe8 && n + 8 <= sizeof (b) && !memcmp (b + n + 5, "\x83\xc4\x04", 3)
					&& b[n + 8] == 0xe8 && b[n + 13] == 0x89 && b[n + 16] == 0xe8) {
					follow_offset (entry, pe->b, b, sizeof (b), pe->big_endian, n + 8);
					int j, calls = 0;
					for (j = 0; j < sizeof (b) - 4; j++) {
						if (b[j] == 0xe8) {
							 
							calls++;
							if (calls == 4) {
								follow_offset (entry, pe->b, b, sizeof (b), pe->big_endian, j);
								return entry;
							}
						}
					}
				}
			}
		}
	}

	 
	if (b[4] == 0xe8) {
		bool found_caller = false;
		if (b[13] == 0xe9) {
			 
			 
			 
			 
			found_caller = follow_offset (entry, pe->b, b, sizeof (b), pe->big_endian, 13);
		} else {
			 
			 
			 
			 
			 
			follow_offset (entry, pe->b, b, sizeof (b), pe->big_endian, 4);
			if (b[9] == 0xe8) {
				 
				 
				 
				 
				 
				follow_offset (entry, pe->b, b, sizeof (b), pe->big_endian, 9);
				if (b[0x129] == 0xe8) {
					 
					found_caller = follow_offset (entry, pe->b, b, sizeof (b), pe->big_endian, 0x129);
				}
			}
		}
		if (found_caller) {
			 
			 
			 
			 
			 
			 
			 
			 
			 
			 
			for (n = 0; n + 14 < sizeof (b); n++) {
				if (b[n] == 0x4c && b[n + 3] == 0x48 && b[n + 6] == 0x8b && b[n + 8] == 0xe8) {
					follow_offset (entry, pe->b, b, sizeof (b), pe->big_endian, n + 8);
					return entry;
				}
				if (b[n] == 0x4c && b [n + 5] == 0x48 && b[n + 10] == 0x8b && b[n + 14] == 0xe8) {
					follow_offset (entry, pe->b, b, sizeof (b), pe->big_endian, n + 14);
					return entry;
				}
			}
		}
	}
	 
	 
	 
	 
	 
	 
	 
	 
	 
	 
	 
	if (b[188] == 0x50 && b[201] == 0xe8) {
		follow_offset (entry, pe->b, b, sizeof (b), pe->big_endian, 201);
		return entry;
	}

	if (b[292] == 0x50 && b[303] == 0xe8) {
		follow_offset (entry, pe->b, b, sizeof (b), pe->big_endian, 303);
		return entry;
	}

	free (entry);
	return NULL;
}