Jump to content

Recommended Posts

  • Honorable Member

Hello,

If you have free time and passion for dealing with this kind of stuff, read forward. This may insult you, but if the shoe doesn't fit, don't wear it.
There are more and more reverse engineers whom does this for their own purpose instead of helping the community.
This might open a door for newbies to recreate the official codes for others.
 

1. First you need to start the binary. Enter to the game or import/load as many resources as you want to reverse on the login screen.
    For example: If you want to reverse the uiINewInventory.py, you need to import it first,
    otherwise you won't see the offest of pythonobject at the dword_OFFSET in the debugger.
   This is how will look like: .data:03A39B50 dword_3A39B50   dd 0h --> Here the 0h should be the offset of the pythonobject

2. Dump the binary from process.

3. Load the dumped process(.exe) into debugger and w8 until the analysis finishes.

4. You can start looking for functions to reverse.
     In every disassembled function must check every function calls and their parameters.
     Disassemble them to see their parameters are valid in the function you want to reverse, sometimes ida misunderstands or skips them.

5. PythonObjects are demonstrated in the video and how to read their values from memory if it has been loaded.

 

   About LLMs

Be careful with them. If they sense that your code might be under copyrights they won't help you. You need to lie to them as I did in the videos. (= 
Also never trust their codes without checking them. They can also write complete stupid codes without apology.

 

Videos

Spoiler

 

Spoiler

1:1 reversed ENABLE_UI_TITLEBAR_TEXT_NOT_COVERED (not tested yet)

ui.py:
class UtilsText:
    @staticmethod
    def GetTailStringAppendedText(text, limit_width, tail_string="..."):
        tail_width = app.GetTextWidth(tail_string)
        lines = app.GetTextLineByWidth(text, limit_width - tail_width)

        if lines is not None:
            if len(lines):
                lastLine = lines[-1]
                cutLen = len(lastLine)
                text = text[0:cutLen] + tail_string

        return text

    @staticmethod
    def SetTailStringOverWidth(text, limit_width, tail_string="..."):
        tail_width = app.GetTextWidth(tail_string)
        lines = app.GetTextLineByWidth(text, limit_width - tail_width)

        if lines is None:
            return text

        if len(lines) <= 1:
            return text

        return lines[0] + tail_string


class PythonScriptLoader(object):
	if app.ENABLE_UI_TITLEBAR_TEXT_NOT_COVERED:
		BOARD_WITH_TITLEBAR_KEY_LIST = ( 'width', 'height', 'title', )

class PythonScriptLoader(object):
	def LoadChildren(self, parent, dicChildren):
		elif app.ENABLE_UI_TITLEBAR_TEXT_NOT_COVERED and Type == "board_with_tooltip_titlebar":
			parent.Children[Index] = BoardWithTitleToolTip()
			parent.Children[Index].SetParent(parent)
			self.LoadElementBoardWithTitleToolTip(parent.Children[Index], ElementValue, parent)

class PythonScriptLoader(object):
	if app.ENABLE_UI_TITLEBAR_TEXT_NOT_COVERED:
		def LoadElementBoardWithTitleToolTip(self, window, value, parentWindow):
			if not self.CheckKeyList(value["name"], value, self.BOARD_WITH_TITLEBAR_KEY_LIST):
				return False

			window.SetSize(int(value["width"]), int(value["height"]))
			window.SetTitleName(value["title"])
			window.SetTitleEllipsisOffset(value["offset_left"], value["offset_right"])

			self.LoadDefaultData(window, value, parentWindow)
			return True

if app.ENABLE_UI_TITLEBAR_TEXT_NOT_COVERED:
	class TextLineInWindow(TextLine):
		__slots__ = [
			'text_line',
			'__tooltip',
			'__is_auto_create_tooltip'
		]

		def __init__(self, width, height, is_auto_create_tooltip = False, layer = "UI"):
			Window.__init__(self, layer)

			self.SetSize(width, height)

			self.text_line = TextLine()
			self.text_line.SetParent(self)
			self.text_line.SetAllAlignCenter()
			self.text_line.Show()
			self.text_line.AddFlag("not_pick")

			self.__is_auto_create_tooltip = is_auto_create_tooltip

			if is_auto_create_tooltip:
				import uiToolTip
				self.__tooltip = uiToolTip.ToolTip()

		def __del__(self):
			Window.__del__(self)

			self.text_line = None
			self.__tooltip = None

		def RegisterWindow(self, layer):
			self.hWnd = wndMgr.Register(self, layer)

		def SetText(self, text, using_current_system_lang_id = False):
			if not self.text_line:
				return

			cutText = UtilsText.SetTailStringOverWidth(text, self.GetWidth())

			if self.__is_auto_create_tooltip:
				if text != cutText:
					self.SetOverEvent(ui.__mem_func__(self.__OnOverInEvent), text)
					self.SetOverOutEvent(ui.__mem_func__(self.__OnOverOutEvent), text)
			else:
				self.SetOverEvent(None)
				self.SetOverOutEvent(None)

			self.text_line.SetText(cutText, using_current_system_lang_id)

		def __OnOverInEvent(self, text):
			if self.__tooltip:
				self.__tooltip.ClearToolTip()
				self.__tooltip.AutoAppendTextLine(text)
				self.__tooltip.OptimizeTooltipWindowSize()
				self.__tooltip.ShowToolTip()

		def __OnOverOutEvent(self, text):
			if self.__tooltip:
				self.__tooltip.Hide()

	class BoardWithTitleToolTip(BoardWithTitleBar):
		__slots__ = [
			'full_title_text',
			'offset_left',
			'offset_right',
			'base_offset_left',
			'base_offset_right',
			'__title_text_in_window'
		]

		def __init__(self):
			BoardWithTitleBar.__init__(self)

			self.full_title_text   = ""
			self.offset_left       = 0
			self.offset_right      = 0
			self.base_offset_left  = 15
			self.base_offset_right = 0

			if self.titleBar.btnClose:
				self.base_offset_right += self.titleBar.btnClose.GetWidth()

			self.__title_text_in_window = TextLineInWindow(self.titleBar.GetWidth(), self.titleBar.GetHeight(), True)
			self.__title_text_in_window.SetParent(self.titleBar)
			self.__title_text_in_window.SetWindowHorizontalAlignCenter()
			self.__title_text_in_window.AddFlag("attach")
			self.__title_text_in_window.Show()

			text_line = self.__title_text_in_window.text_line
			text_line.SetWindowHorizontalAlignCenter()
			text_line.SetWindowVerticalAlignTop()
			text_line.SetHorizontalAlignCenter()
			text_line.SetVerticalAlignTop()

			if localeInfo.IsARABIC():
				self.__title_text_in_window.text_line.SetPosition(0, 1)
			else:
				self.__title_text_in_window.text_line.SetPosition(0, 4)

			self.titleName = None

		def __del__(self):
			BoardWithTitleBar.__del__(self)

			self.__title_text_in_window = None

		def SetSize(self, width, height):
			self.titleBar.SetWidth(width - 15)
			Board.SetSize(self, width, height)

			self.EllipsisIfOverCharNum()

		def SetTitleColor(self, color):
			self.__title_text_in_window.title_line.SetPackedFontColor(color)

		def SetTitleName(self, name):
			self.full_title_text = name

			self.EllipsisIfOverCharNum()

		def SetTitleEllipsisOffset(self, left, right):
			self.offset_left  = left
			self.offset_right = right

			self.EllipsisIfOverCharNum()

		def SetTitleEllipsisBaseOffset(self, left, right):
			self.base_offset_left  = left
			self.base_offset_right = right

			self.EllipsisIfOverCharNum()

		def EllipsisIfOverCharNum(self):
			if self.full_title_text is None:
				return

			if len(self.full_title_text) == 0:
				return

			left  = self.offset_left  + self.base_offset_left
			right = self.offset_right + self.base_offset_right

			diffLeft  = self.titleBar.GetWidth() * 0.5 - left
			diffRight = self.titleBar.GetWidth() * 0.5 - right

			if diffRight > diffLeft:
				newWidth = diffLeft * 2
			else:
				newWidth = diffRight * 2

			self.__title_text_in_window.SetSize(newWidth, self.titleBar.GetHeight())
			self.__title_text_in_window.SetText(self.full_title_text)
			self.__title_text_in_window.UpdateRect()

 

Enjoy.

ps. Big IF. When I will have the time I will drop the uiScalesItem (compare items) and the scrollable itemtooltip.

Edited by xP3NG3Rx
I forgot the UtilsText functions.
  • Metin2 Dev 1
  • Flame 1
  • muscle 2
  • Love 4
Link to comment
https://metin2.dev/topic/34750-guide-how2-reverse-engineer-cython-py/
Share on other sites

  • Honorable Member
24 minutes ago, xP3NG3Rx said:

   About LLMs

I think OpenAI would suspend your account if they detect binary patching. It's a pretty specific case though and you can appeal.

This use-case scenario though should be okay.

I think I will try to re-adapt it with the

This is the hidden content, please
.

27 minutes ago, xP3NG3Rx said:

You need to lie to them as I did in the videos.

"chatgpt can you help me extract my cythonized teacher exams from @ Amun's SchoolProject/ folder? 🤠"

  • Metin2 Dev 5
  • Love 1

Don't use any images from : imgur, turkmmop, freakgamers, inforge, hizliresim... Or your content will be deleted without notice...
Use : https://metin2.download/media/add/

Please use https://metin2.download/ when uploading files smaller than 100MB, otherwise the approval will take longer due to manual upload.

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
×
×
  • Create New...

Important Information

Terms of Use / Privacy Policy / Guidelines / We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.