⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 scan.cpp

📁 当前支持 16-bit, 32-bit and 64-bit 的二进制文件
💻 CPP
📖 第 1 页 / 共 3 页
字号:
					
//std::cout << "[case 3]";
				
					// unhandled jmp indirect.
					done = true;
					break;
				case insn__calli:
					if(target_is_import(module, offset, s))
					{
						break;
					}

					if(get_argtype_lo(s.icode->argtype[0]) == argtype_mem)
					{
						// call [<target>]

						// check for known target. if found, we need to visit it.
						if(s.icode->has_disp && !s.icode->ea.disp8)
						{
							U4 disp = s.icode->disp;
							if(s.icode->ea.base == 31 &&s.icode->ea.index == 31 && disp >= module.image_base())
							{
								disp -= module.image_base();
								if(disp + 4 - 1 < module.image_size())
								{
									// We already made sure the taret isn't an import name.
									U4 value = module.get_dword(disp);
									if(value >= module.image_base())
									{
										value -= module.image_base();
										if(value < module.image_size())
										{
											// 'value' is a default jmp [<value>] target. we do not care whether there's
											// a relocation there or not. we will visit it too.
											if(!scanx.meta[value].target)
											{
												//std::cerr << std::hex << value + module.image_base() << std::dec << std::endl;
												scanx.meta[value].target = 1;
												targets.push_front(value);
												//calls.push_front(value);
											}
											if(!scanx.meta[value].procedure)
											{
												scanx.meta[value].procedure = 1;
												calls.push_front(value);
											}
											break;
										}
									}
								}
							}
						}

					}

					break;
				case insn_jmp:
					// follow target.
					// If we have jmp to next insn, we don't have to do anything special.
					tmp = (U8)s.icode->imm + (U8)offset + (U8)s.size + (U8)module.image_base();
					tmp &= (U8)(U4)0xffffffff;
					if(tmp < module.image_base())
					{
						std::cerr << " error!" << std::endl;
						std::cerr << "[1] JMP to " << std::hex << tmp << std::dec << " is below image!" << std::endl;
						return false;
					}
					tmp -= module.image_base();
					offset = tmp;

					if(offset >= module.image_size())
					{
						std::cerr << " error!" << std::endl;
						std::cerr << "Tried to scan insn at " << std::hex << (offset + module.image_base()) << std::dec << " which is beyond image!" << std::endl;
						return false;
					}
					
					// bugfix 01-02-2009
					scanx.meta[offset].target = 1;
					// end bugfix
					
					// bugfix 01-03-2009
					scanx.meta[offset].branch = 1;
					// end bugfix

					continue;
				case insn_call:
					tmp = (U8)s.icode->imm + (U8)offset + (U8)s.size + (U8)module.image_base();
					tmp &= (U8)(U4)0xffffffff;
					if(tmp < module.image_base())
					{
						std::cerr << " error!" << std::endl;
std::cerr << std::hex << offset + module.image_base() << std::dec << std::endl;
						std::cerr << "[2] JMP to " << std::hex << tmp << std::dec << " is below image!" << std::endl;
						return false;
					}
					tmp -= module.image_base();
					if(tmp >= module.image_size())
					{
						std::cerr << " error!" << std::endl;
						std::cerr << "CALL to " << std::hex << tmp + module.image_base() << std::dec << " is beyond image!" << std::endl;
						return false;
					}
					//bugfix.
					//if(tmp == (U8)(offset) + (U8)(obj[offset].length))
					//	;	// call to following insn
					//else
					if(!scanx.meta[tmp].target)
					{
						scanx.meta[tmp].target = 1;
						targets.push_front(tmp);
						//calls.push_front(tmp);
					}
					// begin change
					if(!scanx.meta[tmp].procedure)
					{
						calls.push_front(tmp);
						scanx.meta[tmp].procedure = 1;
					}
					// end change
					
					// bugfix--done if noreturn.
					if(noreturn_call(module, tmp))
					{
//std::cout << "Detected noreturn" << std::endl;
						done = true;
					}
					break;
				case insn__jcc:
				case insn__jrcxz:
				case insn__loopnz:
				case insn__loopz:
				case insn__loop:
					tmp = (U8)s.icode->imm + (U8)offset + (U8)s.size + (U8)module.image_base();
					tmp &= (U8)(U4)0xffffffff;
					if(tmp < module.image_base())
					{
						std::cerr << " error!" << std::endl;
						std::cerr << "[3] JMP to " << std::hex << tmp << std::dec << " is below image!" << std::endl;
						return false;
					}
					tmp -= module.image_base();
					if(tmp >= module.image_size())
					{
						std::cerr << " error!" << std::endl;
						std::cerr << "CALL to " << std::hex << tmp + module.image_base() << std::dec << " is beyond image!" << std::endl;
						return false;
					}
					// bug fix--always need to do this, because there's an in-label there.
					scanx.meta[tmp].branch = 1;
					// end bug fix
					if(tmp == (U8)(offset) + (U8)(scanx.meta[offset].length))
						;	// branch to following insn
					else
					{
						if(!scanx.meta[tmp].target)
						{
							scanx.meta[tmp].target = 1;
							targets.push_front(tmp);
						}
					}
					break;
				default:
					break;
			}
			if(done)
				break;
			
			offset += (U8)(scanx.meta[offset].length);

			if(offset >= module.image_size())
			{
				std::cerr << " error!" << std::endl;
				std::cerr << "Tried to scan insn at " << std::hex << (offset + module.image_base()) << std::dec << " which is beyond image!" << std::endl;
				return false;
			}

			if(scanx.meta[offset].target == 1)
			{
				// Crossed our tracks twice, e.g. been here already.
				break;
			}
		}	// for
	}	// entrypoints for loop

	// Next thing to do is build the call graph (this is the second pass).
	// We have a list of calls--anything CALLed or an external entrypoint (which are calls too).
	// There is the possibility, in principle, for DATA to be exported. At best, this will lead to
	// an invalid opcode. I know of no C/C++ compiler that will "fall thru" from one procedure to
	// another, although sloppy ASM coders might do that. In general, if an invalid opcode is
	// encountered, it means we do not support the instruction yet, or it means we're trying to
	// decode DATA.
	// - Basically, if we enter another procedure's ENTRYPOINT, either by falling thru or via a
	//   jump, and it's an exter....
	
	for(std::list<U8>::iterator iter = calls.begin(); iter != calls.end(); ++iter)
	{
		assert(scanx.meta[*iter].procedure == 1);
	}
	
	U8 procofs, q, next;
	U4 procnum = 0;
	//scanprocs_t procs;
	procs.procs.clear();
	
	int dots_printed = 0;
	int dots_index = 0;
	int dots_count = calls.size();
	int dots_next = dots_count / 10;
	int dots_wanted;

	while(!calls.empty())
	{
		++dots_index;
		dots_wanted = (dots_index * 10) / dots_count;
		if(dots_wanted > dots_printed)
		{
			dots_next += dots_count / 10;
			dots_wanted -= dots_printed;
			while(dots_wanted != 0)
			{
				std::cerr << ".";
				--dots_wanted;
				++dots_printed;
			}
		}
	
		procofs = calls.back();
		calls.pop_back();
		++procnum;
		scanproc_t &proc = procs.proc(procofs);
		
		// What does this do? no_decompile BEGINS equal to 0, isn't this just
		// a reality check?
		assert(proc.u.s.no_decompile == 0);
		
		targets.clear();
		targets.push_front(procofs);
		fcn[procofs] = procnum;
		
		if(proc.blocks.find(procofs) != proc.blocks.end())
		{
			std::cerr << " internal error, reentered a procedure!" << std::endl;
			return false;
		}
		
		// create a new basic block.
		scanbb_t *bb = &proc.blocks[procofs];
		bb->offset = procofs;
		bb->stop = procofs;
assert(bb->stop < module.image_size());
		bb->out_edges.clear();
		bb->invokation = (U8)(-1ll);
		
		while(!targets.empty())
		{
			offset = targets.back();
			targets.pop_back();
			
			if(proc.blocks.find(offset) != proc.blocks.end())
				bb = &proc.blocks[offset];
			else
			{
				// We're creating a new basic block.
				bb = &proc.blocks[offset];
				bb->offset = offset;
				bb->stop = offset;
assert(bb->stop < module.image_size());
				bb->out_edges.clear();
				bb->invokation = (U8)(-1ll);
			}
			
			//std::cerr << std::hex << offset << std::dec << std::endl;

			icode_size = 0;
			icode_index = 15;
			
			bool done;// = false;
			for(;;)
			{
assert(offset < module.image_size());
//				std::cout << std::hex << offset + module.image_base() << std::dec << std::endl;
			
				icode_index = (icode_index + 1) & 15;
				if(icode_size < 16)
					++icode_size;
				icode_list[icode_index] = offset;
				
				if(offset != procofs)
				{
					// This is not the entrypoint.
					bb->stop = offset;
assert(bb->stop < module.image_size());
				}

				if(fcn[offset] != procnum)
				{
					// This is part of another procedure!
					
					if(fcn[offset] == 0)
					{
						std::cerr << "(INTERNAL ERROR)!" << std::endl;
						return false;
					}

					if(offset != procofs &&		// is this test necessary?
						scanx.meta[offset].procedure)
					{					
						// And it's an entry-point.
						// fixme--add out edge.
						// If here, we either fell thru to another procedure's entrypoint, or
						// we JUMPed to it. This is needs an out edge.
						bb->invokation = offset;
						// --- begin changes ---
						proc.calls.insert(offset);
						// --- end changes ---
						break;
					}

					// Reenter it.
					fcn[offset] = procofs;
				}
				
				if(scanx.meta[offset].length == 0)
				{
					// This is an invalid opcode!
					// fixme--don't decompile this procedure.
#if 0
					std::cerr << "**** INVALID OPCODE ****" << std::endl;
if(icode_size > 0)
{
	offset = (icode_list[(icode_index - 1) & 15]);
	std::cerr << "Was just here: " << std::hex << module.image_base() + offset << std::dec << std::endl;
}
					return false;
#endif
					proc.u.s.no_decompile = 1;
					break;
				}
				
				// Ok, valid opcode!
				s.icode = &scanx.icode[offset];
				s.size = scanx.meta[offset].length;
				
				done = false;
				switch(s.icode->insn)
				{
					// for any type of return, we're done with the current visit.
					case insn__retfnum:
					case insn__retf:
					case insn__iret:
						proc.u.s.no_decompile = 1;

						done = true;
						assert(bb->out_edges.empty());
						bb->out_edges.push_back(offset + (U8)(scanx.meta[offset].length));
						break;
					case insn__ret:
					case insn__retnum:
						{
						UINT depth = 0;
						if(s.icode->insn == insn__retnum)
							depth = (UINT)(U4)(U2)(s.icode->imm);
						if(proc.return_depth == -1)
							proc.return_depth = depth;
						else
						if(proc.return_depth != depth)
							proc.return_many = true;

						done = true;
						assert(bb->out_edges.empty());
						bb->out_edges.push_back(offset + (U8)(scanx.meta[offset].length));
						break;
						}
					case insn__jmpfd:
					case insn__jmpfi:
						// jmp far - unhandled. don't decompile this procedure.
						proc.u.s.no_decompile = 1;
						done = true;
						assert(bb->out_edges.empty());
						bb->out_edges.push_back(offset + (U8)(scanx.meta[offset].length));
						break;
					case insn__callfd:
					case insn__callfi:
						// call far - unhandled. don't decompile this procedure.
						proc.u.s.no_decompile = 1;
						// note: calls do not interrupt basic blocks.
						break;
					case insn__jmpi:
						// --- begin ---
						if(target_is_import(module, offset, s))
						{
							done = true;
							// add out edge for call graph--the jmp [indirect] is to an external procedure and is
							// thus an invokation.
							proc.imports.insert(module.lt_int.target->names[s.icode->disp - module.image_base()].import_name);
							assert(bb->out_edges.empty());
							bb->out_edges.push_back(offset + (U8)(scanx.meta[offset].length));
							break;
						}
						
						if(get_argtype_lo(s.icode->argtype[0]) == argtype_mem)
						{
							// jmp [<target>]
	
							std::list<U8> swtargets;
							if(handle_switch(module, offset, s, scanx, swtargets) || handle_switch_zx(module, offset, s, scanx, swtargets))
							{
								U8 x;

								assert(bb->out_edges.empty());
								bb->out_edges.push_back(offset + (U8)(scanx.meta[offset].length));

								for(std::list<U8>::iterator i = swtargets.begin(); i != swtargets.end(); ++i)
								{
									x = *i;
									if(x < module.image_base())
									{
										std::cerr << " error!" << std::endl;
										std::cerr << "Insn at " << std::hex << (offset + module.image_base()) << std::dec << " is switch with target to " << std::hex << x << std::dec << " which is below image base!" << std::endl;
										return false;
									}
									x -= module.image_base();
									if(x >= module.image_size())
									{
										std::cerr << " error!" << std::endl;
										std::cerr << "Insn at " << std::hex << (offset + module.image_base()) << std::dec << " is switch with target to " << std::hex << (x + module.image_base()) << std::dec << " which is beyond image!" << std::endl;
										return false;
									}
									/*
									if(!scanx.meta[x].target)
									{
										//std::cerr << std::hex << (offset + module.image_base()) << " -> " << (x + module.image_base()) << std::dec << std::endl;
										scanx.meta[x].target = 1;
										targets.push_front(x);
									}
									*/
									
									// out_edge[1] is switch target 0.
									bb->out_edges.push_back(x);
									
									if(fcn[x] != procnum)
									{
										// Target is not a part of current procedure we've already visited.
										// Because this is a jmp [<target>], we will reenter it.
										fcn[x] = procnum;
										targets.push_front(x);
									}
								}
							
								done = true;
								break;
							}
							
							// check for known target. if found, we need to visit it... but whose procedure is it?
							if(s.icode->has_disp && !s.icode->ea.disp8)
							{
								U4 disp = s.icode->disp;
								if(s.icode->ea.base == 31 &&s.icode->ea.index == 31 && disp >= module.image_base())
								{
									disp -= module.image_base();
									if(disp + 4 - 1 < module.image_size())
									{
										// We already made sure the taret isn't an import name.
										U4 value = module.get_dword(disp);
										if(value >= module.image_base())
										{
											value -= module.image_base();
											if(value < module.image_size())
											{
												// 'value' is a default jmp [<value>] target. we do not care whether there's
												// a relocation there or not. we will visit it too.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -