int AddBreakpoint(unsigned long addr, unsigned int type) {
t_polymorphicbreakpoint crt_breakpoint;

	if(numberofpatch>=__MAX_PMBP__) {
		olly_add_to_list(0, __ERROR__, "[Error at %x08X] Too many breakpoint are already set.", addr);
		return 0;
	}

	crt_breakpoint.index=numberofpatch;
	crt_breakpoint.addr=addr;
	crt_breakpoint.type=type;
	crt_breakpoint.able=1;	

	if(Readmemory(tpatch[numberofpatch].original, addr, (unsigned long)size[crt_breakpoint.type], MM_RESILENT) == 0) {
		olly_add_to_list(0, __ERROR__, "[Error at %x08X] Can't read the memory.", addr);
		return 0;
	}
	
	if(Writememory(polymorph[crt_breakpoint.type], addr, (unsigned long)size[crt_breakpoint.type], MM_RESILENT) == 0) {
		olly_add_to_list(0, __ERROR__, "[Error at %x08X] Can't write the memory / Set the breakpoint.", addr);
		return 0;
	}

	tpatch[numberofpatch].addr = addr;
	tpatch[numberofpatch].size = size[crt_breakpoint.type];

	olly_add_sorted_data(&(breakpoint.data),&crt_breakpoint);
	olly_add_to_list(0,0,"New breakpoint at 0x%08X", addr);

	numberofpatch++;

	return 1;
}
int DisableBreakpoint(t_polymorphicbreakpoint *crt_breakpoint) {

	if(Writememory(tpatch[crt_breakpoint->index].original, tpatch[crt_breakpoint->index].addr,
		tpatch[crt_breakpoint->index].size, MM_RESILENT) == 0) {
		olly_add_to_list(0, __ERROR__, "[Error at %x08X] Can't write the memory / Restore the breakpoint.", crt_breakpoint->addr);
		return 0;
	}

	crt_breakpoint->able = 0;

	olly_add_to_list(0,0,"Breakpoint at %08X(%d) disabled", crt_breakpoint->addr, crt_breakpoint->index);

	return 1;

}
void paimei_xmit_location (t_dump *pd)
{
    t_module *tmod;
    char     buf[128];
    size_t   len;

    if (!connection)
    {
        olly_add_to_list(0, 1, "connect to paimei receiver first.");
        return;
    }

    if (!pd)
    {
        olly_add_to_list(0, 1, "no current item to xmit.");
        return;
    }

    tmod = olly_find_module(pd->sel0);

    // null terminate the short name.
    tmod->name[SHORTLEN] = 0;

    olly_add_to_list(0, 0, "%08x is in %s based at %08x", pd->sel0, tmod->name, tmod->base);

    sprintf(buf, "%s:%08x\n", tmod->name, pd->sel0 - tmod->base);
    len = strlen(buf);

    // connection to server successful.
    if (send(connection, buf, len, 0) != len)
    {
        closesocket(connection);
        WSACleanup();
        connection = NULL;
    }
}
LRESULT CALLBACK polybp_winproc(HWND hw,UINT msg,WPARAM wp,LPARAM lp) {

HMENU menu;
unsigned int i;
unsigned long retaddr;
t_polymorphicbreakpoint	*slt_breakpoint;
t_thread *pthread;

	switch (msg) {
		case WM_DESTROY:
		case WM_MOUSEMOVE:
		case WM_LBUTTONDOWN:
		case WM_LBUTTONDBLCLK:
		case WM_LBUTTONUP:
		case WM_RBUTTONDOWN:
		case WM_RBUTTONDBLCLK:
		case WM_HSCROLL:
		case WM_VSCROLL:
		case WM_TIMER:
		case WM_SYSKEYDOWN:
		case WM_USER_SCR:
		case WM_USER_VABS:
		case WM_USER_VREL:
		case WM_USER_VBYTE:
		case WM_USER_STS:
		case WM_USER_CNTS:
		case WM_USER_CHGS:
		case WM_WINDOWPOSCHANGED:
			return olly_table_function(&breakpoint,hw,msg,wp,lp);

		case WM_USER_MENU:

			slt_breakpoint=(t_polymorphicbreakpoint *)olly_get_sorted_by_selection(&(breakpoint.data),breakpoint.data.selected);
			menu=olly_create_popup_menu();

			if (menu != 0 && slt_breakpoint != 0) {

				olly_append_menu(menu,MF_STRING,1,"Follow\tEnter");
				olly_append_menu(menu,MF_STRING,2,"Disable\tDel");

				i = olly_table_function(&breakpoint,hw,WM_USER_MENU,0,(LPARAM)menu);

					if (menu != 0) DestroyMenu(menu);

					if(i==1) olly_set_cpu(0,slt_breakpoint->addr,0,0,CPU_ASMHIST|CPU_ASMCENTER|CPU_ASMFOCUS);

					if(i==2) {
						/* Remove a PolyMorphic Breakpoint */

						if((slt_breakpoint->able == 1) && (ispaused == 1)) {
								
							switch(slt_breakpoint->type) {

							case 0:
								pthread=olly_find_thread(olly_get_cpu_thread_id());
								context = pthread->context;
								
								if((context.Eip >= slt_breakpoint->addr+4) && (context.Eip < slt_breakpoint->addr + 12)) {
									
									// Ajust esp
									context.Esp += 4;
									pthread->reg.r[4] += 4;
									// Restore eip
									context.Eip = slt_breakpoint->addr;
									pthread->reg.ip = slt_breakpoint->addr;
									

								}
									// Delete
									DisableBreakpoint(slt_breakpoint);
							break;
							
							case 1:
								pthread=olly_find_thread(olly_get_cpu_thread_id());
								context = pthread->context;
								
								if((context.Eip >= slt_breakpoint->addr+4) && (context.Eip < slt_breakpoint->addr + 17)) {

									// Ajust esp
									context.Esp += 4;
									pthread->reg.r[4] += 4;
									// Restore eip
									context.Eip = slt_breakpoint->addr;
									pthread->reg.ip = slt_breakpoint->addr;

								}
									// Delete
									DisableBreakpoint(slt_breakpoint);

							break;

							case 2:
								
									// Delete
									DisableBreakpoint(slt_breakpoint);

							break;

							case 3:
								pthread=olly_find_thread(olly_get_cpu_thread_id());
								context = pthread->context;

								if((context.Eip >= slt_breakpoint->addr+4) && (context.Eip < slt_breakpoint->addr + 15)) {

									// Ajust esp
									context.Esp += 4;
									pthread->reg.r[4] += 4;
									// Restore eip
									pthread->reg.ip = slt_breakpoint->addr;
									context.Eip = slt_breakpoint->addr;


								}
								else if(context.Eip == context.Esp) {

									if(Readmemory(&retaddr,pthread->reg.r[4]+2,4,MM_RESILENT) == 0) {
										olly_add_to_list(0, __ERROR__, "[Error at %x08X] Can't read the memory.", pthread->reg.r[4]+2);
										break;
									}
									if(retaddr == slt_breakpoint->addr+5) {

									// Ajust esp
									context.Esp += 6;
									pthread->reg.r[4] += 6;
									// Restore eip
									pthread->reg.ip = slt_breakpoint->addr;
									context.Eip = slt_breakpoint->addr;

									}

								}
									// Delete
									DisableBreakpoint(slt_breakpoint);
							break;

							} // switch(slt_breakpoint->type)
						} // pause

					} // ifremove

				InvalidateRect(hw,NULL,FALSE);

		}
		return 0;

		case WM_USER_DBLCLK:
			slt_breakpoint=(t_polymorphicbreakpoint *)olly_get_sorted_by_selection(
				&(breakpoint.data),breakpoint.data.selected);
				if(slt_breakpoint != 0)
					olly_set_cpu(0,slt_breakpoint->addr,0,0,CPU_ASMHIST|CPU_ASMCENTER|CPU_ASMFOCUS);
		return 0;

		case WM_KEYDOWN:
			if (wp==VK_RETURN && (GetKeyState(VK_SHIFT) & 0x8000)==0 && (GetKeyState(VK_CONTROL) & 0x8000)==0) {
				slt_breakpoint=(t_polymorphicbreakpoint *)Getsortedbyselection(
						&(breakpoint.data),breakpoint.data.selected);
						if(slt_breakpoint!=NULL)
							olly_set_cpu(0,slt_breakpoint->addr,0,0,CPU_ASMHIST|CPU_ASMCENTER|CPU_ASMFOCUS);
			}
		return 0;

        case WM_USER_CHALL:
        case WM_USER_CHMEM:
            InvalidateRect(hw, NULL, FALSE);
            return 0;
        case WM_PAINT:
            olly_paint_table(hw, &breakpoint, polybp_get_text);
		return 0;

		default:
		break;
	}

	return DefMDIChildProc(hw,msg,wp,lp);
}
void paimei_connect (void)
{
    hostent      *he;
    sockaddr_in  sin;
    in_addr      addr;
    WSADATA      wsa_data;

    char server[256];

    memset(server, 0, sizeof(server));
    strcpy(server, "127.0.0.1");

    // if we are already connected then to do nothing.
    if (connection)
        return;

    if (Gettext("PaiMei Server:", server, 0x00, NM_NONAME, FIXEDFONT) == -1)
        return;

    // initialize winsock.
    if (WSAStartup(MAKEWORD(2, 2), &wsa_data) != 0)
    {
        olly_add_to_list(0, 1, "[!] "PLUGIN_NAME"> WSAStartup() failed.");
        return;
    }

    // confirm that the requested winsock version is supported.
    if (LOBYTE(wsa_data.wVersion) != 2 || HIBYTE(wsa_data.wVersion) != 2)
    {
        WSACleanup();
        olly_add_to_list(0, 1, PLUGIN_NAME"> Winsock version 2.2 not found.");
        return;
    }

    // if the provided server address is a hostname, then resolve it with gethostbyname().
    if (isalpha(server[0]))
    {
        if ((he = gethostbyname(server)) == NULL)
        {
            olly_add_to_list(0, 1, "[!] "PLUGIN_NAME"> Unable to resolve name: %s", server);
            return;
        }
    }
    // otherwise resolve the server address with gethostbyaddr().
    else
    {
        addr.s_addr = inet_addr(server);

        if ((he = gethostbyaddr((char *)&addr, sizeof(struct in_addr), AF_INET)) == NULL)
        {
            olly_add_to_list(0, 1, "[!] "PLUGIN_NAME"> Unable to resolve address");
            return;
        }
    }

    // create a socket.
    if ((connection = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
    {
        WSACleanup();
        olly_add_to_list(0, 1, "[!] "PLUGIN_NAME"> Failed to create socket.");
        return;
    }

    // connect to the server.
    sin.sin_family = AF_INET;
    sin.sin_addr   = *((LPIN_ADDR)*he->h_addr_list);
    sin.sin_port   = htons(7033);

    if (connect(connection, (SOCKADDR *) &sin, sizeof(sin)) == SOCKET_ERROR)
    {
        WSACleanup();
        olly_add_to_list(0, 1, "[!] "PLUGIN_NAME"> Failed to connect to server.");
        return;
    }
}