HGLOBAL CCmdLog::CopyLog(int row) { LPLOGGER plog = nullptr; int count = 0; int i; if (m_Table.mode & TABLE_STDSCR) { for (i = 0; ; ++i, count += plog->rows) { plog = reinterpret_cast<LPLOGGER> ( Getsortedbyselection(&m_Table.sorted, i) ); if (plog == nullptr) return nullptr; if (i != row) continue; m_Table.mode &= ~TABLE_STDSCR; HGLOBAL hMem = CopyRow(count, plog->rows); m_Table.mode |= TABLE_STDSCR; return hMem; } } else { for (i = 0; ; ++i, count += plog->rows) { plog = reinterpret_cast<LPLOGGER> ( Getsortedbyselection(&m_Table.sorted, i) ); if (plog == nullptr) return nullptr; int end = count+static_cast<int>(plog->rows); if (row >= count && row < end) { return CopyRow(count, plog->rows); } } } // It should not be run here .. return nullptr; }
// Custom table function of hitlist window. Here it is used only to process // doubleclicks (custom message WM_USER_DBLCLK). This function is also called // on WM_DESTROY, WM_CLOSE (by returning -1, you can prevent window from // closing), WM_SIZE (custom tables only), WM_CHAR (only if TABLE_WANTCHAR is // set) and different custom messages WM_USER_xxx (depending on table type). // See documentation for details. long HitlistSelfunc(t_table *pt,HWND hw,UINT msg,WPARAM wp,LPARAM lp) { t_hitlist * item; switch (msg) { case WM_USER_DBLCLK: // Doubleclick // Get selection. item=(t_hitlist *)Getsortedbyselection(&(pt->sorted),pt->sorted.selected); // Follow address in CPU Disassembler pane. Actual address is added to // the history, so that user can easily return back to it. if (item!=NULL) Setcpu(0,item->index,0,0,0, CPU_ASMHIST|CPU_ASMCENTER|CPU_ASMFOCUS); return 1; default: break; }; return 0; };
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); }
// If column is DF_CACHESIZE, this function must return the requested // size of the data cache. If column is DF_FILLCACHE, DF_FREECACHE or // DF_NEWROW, it must return 0. In all other cases, it must return the // length of the displayed string s in wide characters (and, if mask is // used, the length of the mask in bytes) int CCmdLog::DrawProc( wchar* str, uchar* mask, int* select, t_table* table, t_sorthdr* sort, int column, void* cache ) { static wchar * cmdtype[] = { // Command types we supported . text("unknow"), text("bat"), text("lua"), text("java"), text("perl"), text("ruby"), text("tool"), text("inline"), text("python"), text("system"), text("multicmd") }; // // Note: // For table with style TABLE_SIMPLE or TABLE_USERDEF, // "t_sorthdr *sort" is the pointer to the index of drawing loop. // LPLOGGER plog; std::wstring *pmsg; std::vector<t_sorthdr> *rows; int len, color, max = TEXTLEN * 2; ulong irow = sort->addr + table->offset; t_sorthdr* thdr = reinterpret_cast<t_sorthdr*>(cache); t_sorthdr* msge = reinterpret_cast<t_sorthdr*>(&thdr[1]); LPLOGGER logger = reinterpret_cast<LPLOGGER>(&msge[1]); // The logger can't be null while drawing .. if (column > DF_NEWROW && logger == nullptr) return 0; if (column > DF_NEWROW && logger->addr == 0) return 0; // The common mask flag . if (irow == table->sorted.selected) *select |= DRAW_SELECT; *select |= DRAW_MASK|DRAW_NEW|DRAW_EXTSEL|DRAW_COLOR; switch (column) { case DF_CACHESIZE: // Request for draw cache size // We require cache for outputing. //----------------------------------------------------- //ulong addr; // std::vector<t_sorthdr> * //ulong size; // The row count of handled logger //ulong type; // The selection index .. //----------------------------------------------------- //ulong addr; // The string offset . //ulong size; // The size of this string buffer //ulong type; // The 0-based index of this line //----------------------------------------------------- //ulong addr; // Nothing changed . //ulong size; // Nothing changed . //ulong type; // Nothing changed . //ulong rows; // Nothing changed . //time_t time; // Nothing changed . //long code; // Nothing changed . //void* msge; // The splited multiline array . return sizeof(t_sorthdr)+sizeof(t_sorthdr)+sizeof(LOGGER); case DF_FILLCACHE: // Request to fill draw cache // Now we need to initialize cache when drawing begins. max = sizeof(t_sorthdr)+sizeof(t_sorthdr)+sizeof(LOGGER); memset_s(cache, max, 0, max); // Zero the cache .. // Needn't allocate the array if it uses single line .. if (table->mode & TABLE_STDSCR) ; else rows = new std::vector<t_sorthdr>; thdr->addr = reinterpret_cast<ulong>(rows); return 0; case DF_FREECACHE: // Request to free cached resources // We need to free cached resources when drawing ends. rows = reinterpret_cast<std::vector<t_sorthdr>*>(thdr->addr); if (table->mode & TABLE_STDSCR) ; else if (rows != nullptr) delete rows; return 0; case DF_NEWROW: // Request to start new row in window // // ---------------> For single line drawing .. // if (table->mode & TABLE_STDSCR) { plog = reinterpret_cast<LPLOGGER>( Getsortedbyselection(&table->sorted, irow) ); if (plog != nullptr && plog->addr != 0) { *logger = *plog; thdr->size = irow; pmsg = reinterpret_cast<std::wstring*>(plog->msge); msge->addr = msge->type = 0; msge->size = pmsg->find_first_of(text('\n')); if (msge->size == std::wstring::npos) msge->size = pmsg->length(); } else logger->addr = 0; // Return a null logger . return 0; // Finish .... } // // ---------------> For multi-line drawing .. // // Find the logger by the row number .. for (plog = logger; irow >= thdr->size + plog->rows; ) { thdr->size += plog->rows; // Goto the next level. plog = reinterpret_cast<LPLOGGER>( Getsortedbyselection(&table->sorted,thdr->type++) ); // Already output all loggers or it's a invalid logger if (!plog || !plog->addr) { logger->addr = 0; return 0; } } // Get the row list .. rows = reinterpret_cast<std::vector<t_sorthdr>*>(thdr->addr); // Save this logger to the cache if it's new .. if (plog != nullptr && plog != logger && plog->addr) { // Copy as a new logger cache and clear old logger rows. *logger = *plog; rows->clear(); // Now parsing message information .. msge->addr = msge->size = msge->type = 0; pmsg = reinterpret_cast<std::wstring*>(plog->msge); std::wstring::const_iterator npos, nend = pmsg->cend(); for (npos = pmsg->cbegin(); npos != nend; ++npos) { if (*npos == TEXT('\n')) { // The line ending .. msge->type = rows->size(); rows->push_back(*msge); msge->addr += msge->size+1; msge->size = 0; } else ++msge->size; // The normal chars .. } if (pmsg->back() != text('\n')) { msge->type = rows->size(); rows->push_back(*msge); } while (rows->size() < plog->rows) { msge->type = rows->size(); msge->size = 0; rows->push_back(*msge); // Insert null logger . } } // Now, get the target row and put it into the cache . msge->type = irow-thdr->size; *msge = rows->at(msge->type); return 0; case 0: // The number of logging item . // Do nothing if it's not the first line . if (irow > thdr->size) return 0; len = ::swprintf_s(str, max, TEXT("%d"), logger->addr); memset_s(mask, max, DRAW_GRAY, len); break; case 1: // The time when logging happen. struct tm stm; localtime_s(&stm, &logger->time); len = ::wcsftime(str, max, TEXT("%I:%M:%S %p"), &stm); memset_s(mask, max, DRAW_NORMAL, len); break; case 2: // The cmd type of execution . // Do nothing if it's not the first line . if (irow > thdr->size) return 0; if (logger->type >= _countof(cmdtype)) break; len = ::wcsnlen_s(cmdtype[logger->type], 10); ::wcsncpy_s(str, max, cmdtype[logger->type], 10); color = logger->code == 0 ? DRAW_NORMAL : DRAW_HILITE; memset_s(mask, max, color, len); break; case 3: // The error code of execution . // Do nothing if it's not the first line . if (irow > thdr->size) return 0; len = ::swprintf_s(str, max, TEXT("%i"), logger->code); color = logger->code == 0 ? DRAW_NORMAL : DRAW_HILITE; memset_s(mask, max, color, len); break; case 4: // The answer of execution . pmsg = reinterpret_cast<std::wstring*>(logger->msge); // Get the color ... color = logger->code == 0 ? DRAW_NORMAL : DRAW_HILITE; // For the single line, need to add G_SINGLE. if (logger->rows == 1) { color = DRAW_HILITE; // Always highlight the first line *str++ = G_CALLDEST; *mask++ = DRAW_GRAPH; --max; *str++ = G_CALLDEST; *mask++ = DRAW_GRAPH; --max; // For multi-line, but doesn't support multi-line outputing } else if (table->mode & TABLE_STDSCR) { color = DRAW_HILITE; // Always highlight the first line *str++ = G_SINGLE; *mask++ = DRAW_GRAPH; --max; *str++ = G_CALLDEST; *mask++ = DRAW_GRAPH; --max; // For the first line, need to add G_BEGIN .. } else if (msge->type == 0) { color = DRAW_HILITE; // Always highlight the first line *str++ = G_BEGIN; *mask++ = DRAW_GRAPH; --max; *str++ = G_CALLDEST; *mask++ = DRAW_GRAPH; --max; // For the last line, need to add G_END .. } else if (msge->type+1 >= logger->rows) { //*str++ = msge->size == 0 ? G_END : G_ENTRY; *str++ = G_END; *mask++ = DRAW_GRAPH; --max; *str++ = G_POINT; *mask++ = DRAW_GRAPH; --max; *str++ = G_SPACE; *mask++ = DRAW_GRAPH; --max; *str++ = G_SPACE; *mask++ = DRAW_GRAPH; --max; // For the body line ... } else { *str++ = msge->size == 0 ? G_BODY : G_ENTRY; *mask++ = DRAW_GRAPH; --max; *str++ = G_POINT; *mask++ = DRAW_GRAPH; --max; *str++ = G_SPACE; *mask++ = DRAW_GRAPH; --max; *str++ = G_SPACE; *mask++ = DRAW_GRAPH; --max; } *str++ = G_SPACE; *mask++ = DRAW_GRAPH; --max; ::wcsncpy_s(str, max, pmsg->c_str()+msge->addr, msge->size); memset_s(mask, max, color, msge->size); len = msge->size + TEXTLEN * 2 - max; break; default: return 0; } return len; // Return the length of the text .. }
// Each window class needs its own window procedure. Both standard and custom // OllyDbg windows must pass some system and OllyDbg-defined messages to // Tablefunction(). See description of Tablefunction() for more details. LRESULT CALLBACK Bookmarkwinproc(HWND hw, UINT msg, WPARAM wp, LPARAM lp) { int i, shiftkey, controlkey; HMENU menu; t_bookmark *pb; switch (msg) { // Standard messages. You can process them, but - unless absolutely sure - // always pass them to Tablefunction(). 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: Tablefunction(&bookmark, hw, msg, wp, lp); break; // Pass message to DefMDIChildProc() // Custom messages responsible for scrolling and selection. User-drawn // windows must process them, standard OllyDbg windows without extra // functionality pass them to Tablefunction(). 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: return Tablefunction(&bookmark, hw, msg, wp, lp); // WM_WINDOWPOSCHANGED is responsible for always-on-top MDI windows. case WM_WINDOWPOSCHANGED: return Tablefunction(&bookmark, hw, msg, wp, lp); case WM_USER_MENU: menu = CreatePopupMenu(); // Find selected bookmark. Any operations with bookmarks make sense only // if at least one bookmark exists and is selected. Note that sorted data // has special sort index table which is updated only when necessary. // Getsortedbyselection() does this; some other sorted data functions // don't and you must call Sortsorteddata(). Read documentation! pb = (t_bookmark *)Getsortedbyselection( &(bookmark.data), bookmark.data.selected); if (menu != NULL && pb != NULL) { AppendMenu(menu, MF_STRING, 1, "&Follow\tEnter"); AppendMenu(menu, MF_STRING, 2, "&Delete\tDel"); }; // Even when menu is NULL, call to Tablefunction is still meaningful. i = Tablefunction(&bookmark, hw, WM_USER_MENU, 0, (LPARAM)menu); if (menu != NULL) DestroyMenu(menu); if (i == 1) // Follow bookmark in Disassembler Setcpu(0, pb->addr, 0, 0, CPU_ASMHIST | CPU_ASMCENTER | CPU_ASMFOCUS); else if (i == 2) // Delete bookmark { Deletesorteddata(&(bookmark.data), pb->index); // There is no automatical window update, do it yourself. InvalidateRect(hw, NULL, FALSE); }; return 0; case WM_KEYDOWN: // Processing of WM_KEYDOWN messages is - surprise, surprise - very // similar to that of corresponding menu entries. shiftkey = GetKeyState(VK_SHIFT) & 0x8000; controlkey = GetKeyState(VK_CONTROL) & 0x8000; if (wp == VK_RETURN && shiftkey == 0 && controlkey == 0) { // Return key follows bookmark in Disassembler. pb = (t_bookmark *)Getsortedbyselection( &(bookmark.data), bookmark.data.selected); if (pb != NULL) Setcpu(0, pb->addr, 0, 0, CPU_ASMHIST | CPU_ASMCENTER | CPU_ASMFOCUS); ; } else if (wp == VK_DELETE && shiftkey == 0 && controlkey == 0) { // DEL key deletes bookmark. pb = (t_bookmark *)Getsortedbyselection( &(bookmark.data), bookmark.data.selected); if (pb != NULL) { Deletesorteddata(&(bookmark.data), pb->index); InvalidateRect(hw, NULL, FALSE); }; } else // Add all this arrow, home and pageup functionality. Tablefunction(&bookmark, hw, msg, wp, lp); break; case WM_USER_DBLCLK: // Doubleclicking row follows bookmark in Disassembler. pb = (t_bookmark *)Getsortedbyselection( &(bookmark.data), bookmark.data.selected); if (pb != NULL) Setcpu(0, pb->addr, 0, 0, CPU_ASMHIST | CPU_ASMCENTER | CPU_ASMFOCUS); return 1; // Doubleclick processed case WM_USER_CHALL: case WM_USER_CHMEM: // Something is changed, redraw window. InvalidateRect(hw, NULL, FALSE); return 0; case WM_PAINT: // Painting of all OllyDbg windows is done by Painttable(). Make custom // drawing only if you have important reasons to do this. Painttable(hw, &bookmark, Bookmarkgettext); return 0; default: break; }; return DefMDIChildProc(hw, msg, wp, lp); };