Advanced+apple+debugging (11)

Source: Internet
Author: User
Tags python script

Swiftobject class: Detours in a detour

But wait a minute, you've probably looked at the Swiftobject class, which is the parent class of the Aswiftclass Class! Let's use image lookup to extract the method of this class implementation.
Enter the following in the LLDB:

(lldb) Image Lookup-rn Swiftobject
Picture. png
I don't know what your output is, but I'm really tired of looking at the output of this ugly format. It's really hard to read these things right. Now that you've been reading this book for so long, you know you're free to make any necessary changes to make your life easier.
Use Lldb's Python API to create a more beautiful query:

(lldb) Script srch = lldb.target.FindGlobalFunctions (' Swiftobject ', 0,lldb.ematchtyperegex)
You declare a sbsymbolcontextlist type of search query and assign it to srch. This is something like a python array of sbsymbolcontext.
I'll leave it to you to grab the Findglobalfunctions document through the Sbtarget in Gdocumentation.
Now enter the following in the LLDB:

(lldb) script print "\ n". Join (Map (Lambda a:str (a.symbol.name), srch))
Here a lambda is used to fetch the function name and then split each object into the list by a newline character.

Picture. png

A little better. Maybe that's a good script for the next chapter. OK, go back to the target in our hands. You are browsing the methods implemented by the Swiftobject class. Note the description and Debugdescription methods implemented by the Swiftobject class.
This allocator project actually swapped the Swiftobject debugdescription to modify the output and display pointers to the Swiftobject subclasses. This logic is found in the nsobject+ds_swiftobject.m file. The swift language and swift LLDB environment hides this pointer, which is very annoying.
The extracted output means that any swift class still opens the runtime for swizzling and objective-c, regardless of whether it inherits from NSObject or is a class that does not have a parent class at all. It is good to keep these in mind for the sake of your application's security.
Memory layout of Swift with NSObject as the parent class

Last point. You know this training, so we'll talk a little faster and skip the actual debugging session.
Check the source code of the Aswiftnsobjectclass.swift:

Class Aswiftnsobjectclass:nsobject {
Let Eyecolor = Uicolor.brown
Let FirstName = "Derek"
Let LastName = "Selander"
Required override Init () {}
}
This is the same content as Aswiftclass, except that it inherits from NSObject rather than inheriting from nothing.
So what is the difference between the pseudo-code of the C struct generated here?

struct Aswiftnsobjectclass {
Class Isa;
uintptr_t referencecounts;
Uicolor *eyecolor;
struct _stringcore {
uintptr_t _baseaddress;
uintptr_t _countandflags;
uintptr_t _owner;
} firstName;
struct _stringcore {
uintptr_t _baseaddress;
uintptr_t _countandflags;
uintptr_t _owner;
} firstName;
}
No, it's not! The pseudo-code generated here is no different from the pseudo-code of Aswiftclass. The biggest difference is that this class has a simpler vipassana because NSObject achieves more than Swiftobject.
Let's skip the debug session and just talk about what happens when you try to retain an instance of the class: the refcounts variable is not modified. This is because OBJECTIVE-C has its own implementation of retain/release that are different from those implemented by Swift.
You can finally learn Sbvalue class I can't wait to tell you!.

Sbvalue

Yes, it's time to talk about this amazing class.
Sbvalue is responsible for interpreting the profiling expressions from your JIT code. Think of Sbvalue as a representation of the member variables that let you navigate your object, just when you do the things above, but without the ugly dereference. Inside the Sbvalue instance, you can easily access all the variables in your struct ..., I mean, your objective-c or Swift class.
In the Sbtarget and Sbframe classes, there is a method called EvaluateExpression, which takes your expression as a Python str and returns a Sbvalue instance. In addition, there is an optional second parameter that allows you to indicate how you want your code to be parsed. You will not use the optional second parameter when you first start, but it will be used later.
Go back to the LLDB console and make sure that the allocator project is still running. Make sure that the LLDB console is in the foreground (that is, the program is paused), empty the console and enter the following:

(LLDB) PO [dsobjectivecobject New]
You will get something similar to the following:

<DSObjectiveCObject:0x61800002eec0>
This ensures that you can create a valid instance of Dsobjectivecobject.
The code is working, so you can apply it to the EvaluateExpression method as a global Sbtarget instance or Sbframe instance:

(lldb) script lldb.frame.EvaluateExpression (' [Dsobjectivecobject new] ')
You will get the usual mysterious output of this class, but without the contextual description of what these do:

<lldb. Sbvalue; Proxy of <swig Object of type ' lldb::sbvalue * ' at0x10ac78b10> >
You have used print to get the context of these classes:

(lldb) script print lldb.target.EvaluateExpression (' [dsobjectivecobjectnew] ')
You will get the debugdescription you like that you have become accustomed to.

(Dsobjectivecobject *) $ = 0x0000618000034280
Note: If you enter something wrong, you will still get an SBValue instance, so make sure it prints out what you expect. For example, if you enter the JIT code incorrectly, you will get something similar from Sbvalue ** = &lt;could not resolvetype&gt;** .
You can confirm Sbvalue success by checking the Sberror instance in your sbvalue. If your sbvalue sbval is called, you're a pass sbval.GetError().Success() , or more simply a sbval.error.success. print way to open a sue to see if it works.
Modify this command so that you can assign this value to the variable a in the Python context:

(lldb) Script a = Lldb.target.EvaluateExpression (' [dsobjectivecobjectnew] ')
Now apply the Python print function to the A variable:

(lldb) script print a
Once again you will get output similar to the following:

(Dsobjectivecobject *) $ = 0x0000608000033260
That's great! You have a sbvalue instance stored in a variable and have seen the dsobjectivecobject memory layout.
You know a holds a sbvalue, this value points to the Dsobjectivecobject class. You can crawl description by using GetDescription () to crawl Dsobjectivecobject, or simpler sbvalue of the Description property.
Enter the following content:

(lldb) script print A.description
You will see something like the following:

<DSObjectiveCObject:0x608000033260>
You can also get the Value property, which returns a pythonstring containing the address of this instance:

(lldb) script print A.value
This time the value is:

0x0000608000033260
Copy the output of the a.value and then make sure that the PO gives you the original pointer, the current reference:

(LLDB) PO 0x0000608000033260
Yes:

<DSObjectiveCObject:0x608000033260>
If you want this address to be represented by a python number instead of a python str, you can use the signed or unsigned property:

(lldb) script print a.signed
Like this:

106102872289888
Formatting this number into a 16 binary will produce a pointer to the Dsobjectivecobject instance:

(LLDB) p/x 106102872289888
Now you'll be in the place where you were before:

(long) $ = 0x0000608000033260
Browse Properties by Sbvalue offset

How are these attributes stored in the Dsobjectivecobject instance? Let's take a look at them!
Use the Sbvalue available Getnumchildren method to get the number of child:

(lldb) script Print A.getnumchildren () 4
You can consider children as an array. Here is a special API to crawl a class of children, this API is called Getchildatindex. Browse children 0-3 in Lldb:
Child 0:

(lldb) script print a.getchildatindex (0)
(NSObject) NSObject = {
ISA = Dsobjectivecobject
}
Child 1:

(lldb) script print A.getchildatindex (1)
(Uicacheddevicergbcolor *) _eyecolor = 0x0000608000070e00
Child 2:

(lldb) script print A.getchildatindex (2)
(__nscfconstantstring *) _FirstName = 0x000000010db83368 @ "Derek"
Child 3:

(lldb) script print A.getchildatindex (3)
(__nscfconstantstring *) _lastname = 0x000000010db83388 @ "Selander"
Each of them will return a sbvalue within itself, so you can even explore that object further if you desire it. Bring the FirstName attribute into the account. Enter the following to get description:

(lldb) script print A.getchildatindex (2). Description
Derek
It is important to remember that Python variable A is a pointer to an object. Enter the following:

(lldb) Script A.size
8
This will print out a value that tells us that a is 8 bytes long. But you want to get the actual content of a! Fortunately, Sbvalue has a Deref property that returns another sbvalue. Browse the output of the Size property:

(lldb) Script A.deref.size
This time the return value is 32 because it is made up of Isa, Eyecolor, FirstName and LastName, each of them is 8 bytes long.

(lldb) script print A.type.name
You will get these:

Dsobjectivecobject *
Now do the same thing with the Deref property:

(lldb) script print A.deref.type.name
Now you will have this common class:

Dsobjectivecobject
View raw data (raw) via Sbvalue

You can even extract the raw data through the Data property in Sbvalue! This is a Sbdata class, you can check this class yourself when you are free.
Print out a pointer to the Dsobjectivecobject data:

(lldb) script print A.data
This will print out the physical bytes that make up the object. Again, this is a pointer to Dsobjectivecobject, not the object itself.

This is a. 2...
Remember that the inner byte in hexadecimal represents two bits.
Do you remember the small end format in the 11th chapter "assembly& Memory" and how the original data was reversed?
Make a comparison of this value with Sbvalue's Value property.

(lldb) script print A.value
0x0000608000033260
Picture. png

Notice how the values are ranked. For example, the last two 16 binary bits of my pointer's raw data are a group. In my case, the 0x60 in the original data is the first value, while the pointer contains the 0x60 as the last value.
Use the Deref property to crawl all the bytes that make up the dsobjectivecobject.
(lldb) script print A.deref.data f054b80d01000000000e070080600000. T ........ 6833b80d010000008833b80d01000000 H3 ... 3 ...
This is another way to visualize what's going on. You skip 8 bytes at a time when you use the PO (ID) (0x0000608000033260 + multiple_of_8) command to view the memory.

Sbexpressionoptions

As we mentioned in our discussion of EVALUATEEXPRESSIONAPI, there is an optional second parameter that will be brought into a sbexpressionoptions instance. You can use this option for JIT execution to pass in a special option.
In Lldb, clear the screen and enter the following:

(lldb) Script options = Lldb. Sbexpressionoptions ()
There will be no output after successful execution of the above command. Next Enter:

(lldb) Script options. SetLanguage (Lldb.elanguagetypeswift)
Sbexpressionoptions has a method called SetLanguage (when in doubt, using Gdocumentation sbexpressionoptions), this method takes a LLDB module enumeration type parameter lldb: : Languagetype. The author of Lldb has a convention to paste an "e" in front of an enumeration, the name of the enumeration, and then the unique value.
This sets the default type to replace hungry as the swift code execution, based on the Sbframe language type.
Now tell the options variable to translate the JIT code as the ID of a (that is, the PO replaces P).

(lldb) Script options. Setcoerceresulttoid ()
The setcoerceresulttoid has an optional Boolean that determines whether it is translated into an ID type. By default, this is set to true.
Summarize what you're doing here: you set the option to parse the expression with the Python API instead of the option passed to us through an expression command. For example, as of now you have declared that the sbexpressionoptions is quite similar to the options in the following expression commands:

Expression-lswift-o--Your_expression_here
Next, just use the expression command to create a Aswiftclass instance method. If this is possible, you will try the same command in the EvaluateExpression command. Enter the following in the LLDB:

(LLDB) E-lswift-o--Aswiftclass ()
You will get the output content will be a bit ugly error ...

Error: <expr>:3:1: Error:use of unresolved identifier ' Aswiftclass '
Aswiftclass ()
^~~
Oh yes, you need to import the allocator module to ensure that Swift works well in the debugger.
In the LLDB:

(LLDB) E-lswift--Import Allocator
Note: This is a problem many lldb users complain about: LLDB does not correctly execute code that should be able to execute. Adding this import logic will modify LLDB's swift expression prefix, which is a collection of basic header files that are correctly referenced before you execute your JIT code.
LLDB cannot see the JIT code when you stop in a non-swift debugging environment ASwiftClass . This means that you need to attach the Allocator header of the expression prefix that belongs to the module. Here is a very good explanation from the author of Lldb about the problem:/HTTP Stackoverflow.com/questions/19339493/why-cant-lldb-evaluate-this-expression.
Execute the previous command again. Press two times up ARROW key and then enter:

(LLDB) E-lswift-o--Aswiftclass ()
You will get a reference to the Aswiftclass () instance.
Now that you know it's doable, use the EvaluateExpression method this time with the options as the second parameter and then assign the output to the variable B, like this:

(lldb) Script B = lldb.target.EvaluateExpression (' Aswiftclass () ', options)
If all goes well, a sbvalue reference will be stored in Python variable B.

Note: It should be noted that some of the properties of Sbvalue do not work well in Swift. For example, deref address_of referencing a Swift object using the Sbvalue or property dereference will not work properly. You can do this by indicating that the pointer is a swiftobject force to point this pointer to a objective-c reference, Then everything will work as usual. As I said, they let you work for it when you try to chase it in Swift!
Referencing variables in Sbvalue by name

It is a rather boring way to see the objects in memory by Getchildatindex referencing the child sbvalues from the Sbvalue. If the author of this class adds a property before Eyecolor, what is the total offset logic when you crawl to this sbvalue?
Fortunately, Sbvalue has another way to refer to instance variables by name instead of offsets: Getvalueforexpressionpath.
Skip back to Lldb and enter the following:

(lldb) script print B.getvalueforexpressionpath ('. FirstName ')
If you want, you can continue practicing your own structure into the following child:

(lldb) script
B.getvalueforexpressionpath ('. Firstname._core._baseaddress._rawvalue '). VA
Lue
How am I or that crazy _core._baseaddress._rawvalue part? If you don't have a clue to Sbvalue's name, all you have to do is use GETINDEXOFCHILDAPI to get the child, Then use the Name property on that child sbvalue.
For example, if I do not know the name of the Uicolor attribute found in Bsbvalue, I may do the following things:

Picture. png
Lldb.value

The last thing you can do is to create a Python reference with the Sbvalue property as a property of the Python object (wait ...). What?). Think of it as an object that you can use to refer to a variable by using a Python property instead of an alternate string.
Back in the console, create a new value object from your Bsbvalue:

(lldb) Script c = Lldb.value (b)
This will create a special Python object of type value. Now you can refer to his instance variable as if it were a normal object!
Enter the following in the LLDB:

(lldb) script print C.firstname
Of course, it's all of its own child properties you can also use. Enter the following content:

(lldb) script print C.firstname._core._countandflags
You will get:

_countandflags = 5
You can also parse a child object into a sbvalue so that you can query it or apply it to a for loop, like this:

(lldb) script print c.firstname._core._countandflags.sbvalue.signed
This will output Python int 5 in the console.
Again, if you don't know the name of child Sbvalue, use Getchildatindexapi to get the child and get its name from the Name property.

Note: Even though lldb.value the class is powerful, there is a cost to it. The performance of creating and accessing properties is considerable. If you are dissecting a large array, using this class will significantly reduce the speed of the operation. Practice using this class and find the balance between speed and performance.
Why do we have to learn this?

Oh, wow! ... How dense is the content of this chapter? Fortunately, you looked at it completely. You can use the options in your custom commands to dynamically generate your JIT script code. From the return value of your JIT code, you can write custom logic scripts that are based on the Sbvalue returned after Evaluateexpressionapi parsing.
This will unlock some surprising scripts for you. In any process you can attach with LLDB, you can return your own custom script and then process the custom values returned by your Python script. This does not have to deal with signature problems or load frameworks problems or other similar issues.
The remainder of this section will focus on creating creative scripts and how these scripts can make your debugging (or reverse engineering) life easier.
The theoretical time is over. It's time to do something fun!

Advanced+apple+debugging (11)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.