summaryrefslogtreecommitdiffstats
path: root/sploit/payload/payload.py (unfollow)
AgeCommit message (Collapse)AuthorFilesLines
2025-01-04Rename sploit package to nsploitMalfurious1-224/+0
Rename all affected files, references to file paths, and module imports within the code. Since this line of development represents a fork from the original sploit, a name change is seen as necessary to distinguish the projects, as well as allow them to be installed side by side. What does the "n" mean? Great question! You can think of it as meaning "new sploit" if you want, though that's not quite intended. The name is simply distinct and easy to pronounce. I had originally settled on "msploit" (something along the lines of "Malf's sploit"), but this name is too close to "metasploit" for me - and N is right next to it on the keyboard. Signed-off-by: Malfurious <m@lfurio.us>
2025-01-02payload: Separate length and bytes calculationsMalfurious1-16/+29
Previously, the len(payload) operation required the generation of the full payload binary content, in order to count how many bytes long it was. This is no longer the case, as there are opportunities for optimizations, primarily regarding fixed-length dynamic payload entries where we can simply grab the size parameter without having to generate a buffer. In addition to potential speedups, this fix also allows the user to insert PayloadEntry pointers for fields which are not yet present in the payload being built (ie: whenever the pointer is to exist before the pointed-to data). Whereas previously, the inability to generate the ill-formed pointer would break length calculations necessary to insert additional data. Signed-off-by: Malfurious <m@lfurio.us>
2025-01-02payload: Improve recursion performanceMalfurious1-14/+22
There is a small network of mutually-recursive helper functions which produce the main outputs for Payload objects (the length, bytes, etc.). The runtime performance of this code can suffer as a Payload grows to contain more and more items. These issues are heavily mitigated by implementing memoization within one of these functions (which propagates the benefit to the rest of the call tree). Memo dictionary is only used for a single operation (lifetime) to avoid the possibility of bad cached results. Signed-off-by: Malfurious <m@lfurio.us>
2025-01-01payload: Refactor as a concrete IndexTblMalfurious1-86/+195
Payload is now an index table, wherein each index is a byte string (or compatible type). The retrieval of indices will return a corresponding offset or address of the indexed data (which is sensitive to the payload base). There is no longer a Symtbl member. Due to this new design, the class no longer keeps a running payload buffer that is appended to every time the payload is updated. When the user wants to get the full data, this buffer is constructed from the Lict elements backing the payload. This allows individual elements to be modified or removed easily after they are inserted. The use of a Lict allows data elements to be referred to by either their positional array index, or the key specified when first creating that element (done using the IndexTbl interface). Payload objects may now be directly nested inside eachother, as opposed to simply taking a payload's bytes and inserting those. This allows payloads to be used in a way resembling C structures. The type-specific insertion functions have been removed and we instead now lean on the __setindex__ interface inherited from IndexTbl to directly assign values and append them to the payload. In this case, values are taken as-is from the assignment if they are bytes-like, and automatically converted in some cases. Payload's __call__ overload is now used to perform the quick, chainable, and inline value insertion that was lost by the removal of the type-specific functions. "Calling" a payload with zero arguments will still provide the old behavior of returning the payload bytes, however. The semi-advanced features such as padding, alignment, and inserting placeholder bytes have been removed from the main payload interface and are now provided as compatible types that can be directly inserted into Payload via the means described above. In most cases, these are now implemented to dynamically react to changes in the Payload content. For example, a "padlen" element, which is constructed with a fixed target length parameter, will grow or shrink in length if the data preceding it changes. Automatic "badbytes" detection is removed, simply due to API conflict. In my experience, this feature was little-used and can easily be done manually by scripts if desired. I don't plan to reintroduce this feature. pad_front functionality is also removed by this patch, since at the moment it doesn't fit into the new design very well. We may attempt to reimplement it as a PayloadEntry down the road. However, this feature has also only seen rare use in my experience. Signed-off-by: Malfurious <m@lfurio.us>
2024-01-13builder: Rename package to payload and expose contentsMalfurious1-0/+0
This follows in the package contents export change. Additionally, the builder package is renamed to "payload". "payload" is actually the preferred name of this package. It was previously renamed due to the absurdity of importing "sploit.payload.payload.Payload()", and the fact that additional modules were being bundled together so a more broad name _seemed_ desirable. Signed-off-by: Malfurious <m@lfurio.us>
2023-03-19payload: Add method end()Malfurious1-0/+3
To determine the address of the end of a payload, based on its Symtbl data. I believe it makes the most sense to make this a part of the Payload API, since Symtbl lacks a concept of element size. Signed-off-by: Malfurious <m@lfurio.us> Signed-off-by: dusoleil <howcansocksbereal@gmail.com>
2023-03-19Create new subpackage 'builder'Malfurious1-0/+0
This is a package to contain the related Payload and ROP modules, as well as utility classes. Payload is moved into the new package. Signed-off-by: Malfurious <m@lfurio.us> Signed-off-by: dusoleil <howcansocksbereal@gmail.com>
2023-03-13payload: Add explicit width intsdusoleil1-0/+16
Signed-off-by: dusoleil <howcansocksbereal@gmail.com> Reviewed-by: Malfurious <m@lfurio.us>
2023-03-13arch: refactor byte/int conversionsdusoleil1-2/+2
The built in int's to_bytes and from_bytes functions have some weird behavior with the signed parameter. Rather than expecting the user to properly give btoi/itob the right signed value to pass through to to_bytes/from_btyes, it makes more sense to just always convert an unsigned number. Using the new int conversions, this can always be unambiguous with respect to the width of the int. There may also be situations where a user would like to truncate/sign extend an int to a certain length other than the configured architecture wordsize or convert to a different endianness. These are now parameterized. There is no need to parameterize the width for btoi because you will now always get an unsigned int back (and because of python, the width is ambiguous). The user can convert it to whatever width/sign they want after the fact with the new int conversion methods. This also means that payload's int() does not need to take a signed argument either. Whatever sign of int you give it, when it calls itob, it will get the correct bytearray at the width of the configured architecture's wordsize. Signed-off-by: dusoleil <howcansocksbereal@gmail.com> Reviewed-by: Malfurious <m@lfurio.us>
2023-02-24symtbl: Refactor module as an improved container type (and more)Malfurious1-3/+3
This effort was triggered by three immediate wants of the module: An improved data container interface to support things like key iteration and better key management. This is primarily wanted by the ROP module (which is still in development). The introduction of package documentation across the project. This module is now fully documented. To fix a bug in the Symtbl constructor, which would not allow a caller to supply "self" as an initial symbol name, even though it is legal in every other context. This problem was caused by the constructor's bound instance parameter sharing this name. This patch addresses all of these concerns, and also introduces some fringe / QoL improvements that were discovered during the API refactor. Element access may now be done via subscripting, as well as the previous (and still generally perferred) .attribute notation. The syntax for storing subtables within a parent Symtbl is now greatly streamlined due to some implementation-level changes to the class. You may now directly assign just a Symtbl object or a normal int, and you don't have to fuss with tuples anymore. The subtable's base is taken as its offset in the parent, and the new operator replacement for the .map() method may be used to define a desired value for the parent. This detail is actually a breaking change compared to the previous version. While not technically a bug, it is unintuitive that the previous version would not remove subtables when their offset was changed by a simple assignment - the table would just move. This patch make it such that any symbol assignment to a regular int will replace an old mounted subtable if one exists. There are now no normal instance methods on the Symtbl type (only dunder method overrides). This is to free up the available symbol namespace as much as possible. The previous methods map(), adjust(), and rebase() are now implemented as operators which, in every case, yield a new derivative object, rather than mutating the original. All operators are listed here: @ remap to absolute address + remap to relative address - remap to negated relative address >> adjust all symbol offsets upward << adjust all symbol offsets downward % rebase all symbol offsets around an absolute zero point Additionally, Symtbl objects will convert to an integer via int(), hex(), oct(), or bin(), yielding the base value. The addition of these operators presents another breaking change to the previous version. Previously, symbol adjustments or rebases affected the tracked offsets and caused symbols to shift around in linked tables as well. Since these operators now preserve the state of their source object, this is no longer the case. The amount of shift due to adjustment or rebasing is localized in a specific Symtbl instance (and is affected the the use of the related operators), however this value is inherited by derivatives of that object. There is a third breaking change caused by the use of operators as well. Previously, the map() function allowed the caller to specify that the given absolute address is not that of the table base, but of some offset in the table, from which the new base is calculated. However, the remapping operators take only a single numeric value as their right hand side operand, which is the absolute or relative address. The new intended way of accomplishing this (which is _nearly_ equivalent) is through the combined use of the rebase and remap operations: # The address of the puts() function in a libc tbl is leaked sym = sym % sym.puts @ leak aka: adjust offsets such that the known point is at the base, then move that base to the known location. The way in which this is different to what you would end up with before is that previously, following a map(abs, off) the base of the table would be accurately valued according to the known information. Now, the 'base' is considered to be the leaked value, but internal offsets are shifted such that they still resolve correctly. Finally, a few new pieces of functionality are added to build out the container API: - symbol key deletion - iteration over symbol:offset pairs - can now check for symbol existence with the "in" keyword - len(symtbl) returns the number of symbols defined Signed-off-by: Malfurious <m@lfurio.us> Signed-off-by: dusoleil <howcansocksbereal@gmail.com>
2023-02-24symtbl: Rename file to match class nameMalfurious1-1/+1
I assume that the preferred style is to leave one major class each to a file. In this case, synchronize the names of the Symtbl class and its containing module. Per PEP8, the module is lowercase, and the class remains Pascal case. If other memory-oriented utilities are introduced in the future, we may wish to move them, as well as Symtbl, back into a subpackage named 'mem'. Signed-off-by: Malfurious <m@lfurio.us> Signed-off-by: dusoleil <howcansocksbereal@gmail.com>
2022-09-12sploit: Fix bugs involving Symtbl base valueMalfurious1-2/+2
Some code previously assumed a Symtbl's base value to always be zero. This was often the case, however the assumption would break (for example) when attempting to rebase() a mapped Symtbl. As of the previous patch enabling freer modification of base, the potentiality of these bugs will be higher. Signed-off-by: Malfurious <m@lfurio.us> Signed-off-by: dusoleil <howcansocksbereal@gmail.com>
2022-09-12sploit: payload: Promote private methods to "protected" accessMalfurious1-15/+15
Lift restriction (name mangling) to Payload helper functions, as their use will be useful in Payload subclasses. Signed-off-by: Malfurious <m@lfurio.us> Signed-off-by: dusoleil <howcansocksbereal@gmail.com>
2022-09-12sploit: payload: Clean up automatic symbol namingMalfurious1-10/+11
This is just a slight code reduction, but will make any future code simpler as well. Explicit comparision to None is more correct as well; centralizing this for reuse better justifies the wordier if statement. Signed-off-by: Malfurious <m@lfurio.us> Signed-off-by: dusoleil <howcansocksbereal@gmail.com>
2022-09-12sploit: payload: Class no longer extends SymtblMalfurious1-11/+8
Given the current design of Symtbl, creating subclasses of it gets more tedious the further one goes down a potential class hierarchy. As I am planning to introduce new features in the future that explicitly extend Payload, make this change now to minimize the impact. Additionally, switching Payload's relationship with Symtbl from "is-a" to "has-a" makes it more consistent with rev.ELF, the other major user of Symtbl. (And in both cases, the member is named 'sym') Signed-off-by: Malfurious <m@lfurio.us> Signed-off-by: dusoleil <howcansocksbereal@gmail.com>
2022-09-12sploit: payload: Allow variadic insertionsMalfurious1-13/+15
Often times, users of the Payload module wish to push a list of integers to a payload buffer. Currently, the best (and intended) way to do this is to make several calls to .int(). However, as part of the ROP effort, I am planning to add function 'gadget(addr, *params)' to the Payload class. Per the design of this function, calling it with an expanded list of values would be equivalent to passing each to .int() individually. In order to discourage the use of .gadget(), as a shortcut to a series of .int()s, .int(), and most other insertion functions, now accept arbitrarily many value arguments. Functions that support additional options (such as .int()'s 'signed' parameter) will apply such options to all values. If a symbol name is defined, it will reference the beginning of the block of values. Keep in mind, this will also allow inserting zero values. For example, obj.bin(sym='end') will tag the end of the payload without extending its content. This use-case is not intended to be particularly useful, but exists as a consequence of the change. Payload.rep() and the pad functions are not affected by this commit, as I don't think changing their semantics in this way makes sense. Signed-off-by: Malfurious <m@lfurio.us> Signed-off-by: dusoleil <howcansocksbereal@gmail.com>
2022-03-17sploit: Rework payload builderMalfurious1-57/+68
The design/implementation of class Payload is updated for better compatibility with Symtbl, and to address some usability issues that have come up so far: No more automatically fixed-up stack alignment by default: In fact, alignment as a concept is fully removed from the tool, in preparation for another upcoming ROP-centric addon to Payload. Therefore, insertion of return addresses (via .ret()) are now equivalent to any other integer value. No instance size value: Each call to .pad() uses an independent size passed as a parameter, but functions in the same manor as before. Padding can also now be inserted at the beginning of the payload: .pad_front() prepends the necessary amount of data, and updates the tracked offsets of values that were already inserted to the payload. Payload now directly extends Symtbl: Instead of possessing a Symtbl member, payload objects can directly be treated as symbol tables for things like mounting them as subtables, or mapping them to access absolute addresses. New call syntax to access binary data: As a shorthand, users may now use the call syntax to get the bytes string built by the tool. If an argument is passed, it is another byte string containing illegal bytes that we check the built payload for. Unfortunately, the __str__ magic func doesn't like returning bytes string; plus, that overload is already in use for formatting the symbol table content (worth not hiding). New semantic insertion functions: .bin(), .str() [C-style strings], .int(), .ret(), and more. Some of these functions are direct synonyms, however their use can provide more clarity in Sploit scripts. Smarter default element symbol names: Instead of just using '_' as a placeholder if no symbol name is ever given, we now uniquely name each inserted element according to the API function that was used, then slap on an incrementing number. An explicit name still bypasses this scheme. Insertion functions can now be chained together: Functions previously returned the offset/address of the inserted value. However, this feature was seldom used, and there is now the possibility of .pad_front() invalidating previously-returned offsets. Instead, functional-style chaining is enabled to reduce boilerplate, and help with quick oneliners. Signed-off-by: Malfurious <m@lfurio.us> Signed-off-by: dusoleil <howcansocksbereal@gmail.com>
2021-09-07sploit: Add payload builder moduleMalfurious1-0/+64
class Payload is a tool for constructing stack-smash payloads and ROP chains. Its design is intended to abstract away some of the more tedious details of crafting a payload. Payload utilizes mem.Symtbl internally to optionally manage a collection of named offsets into its own buffer (these are usually in reference to entities appended to the payload via its main API). Alternatively, the API calls to append any entity will return the address of that entity as well. Returned (and looked-up) addresses are relative to the beginning of the payload by default. However, when the payload is constructed with a known base address value, these become absolute. This is useful for reusing addresses later in the payload body. class Placeholder is designed to be functionally compatible with bytearrays and bytestrings. When constructed, they take the value of 'zero', according to the current arch config. This facility enables some API's to detect whether a dummy value was passed as a required argument when said argument _may_ be unnecessary in niche situations. Signed-off-by: Malfurious <m@lfurio.us> Signed-off-by: dusoleil <howcansocksbereal@gmail.com>