6 votes

Appeler getsectiondata depuis Swift

Cette question et cette réponse décrivent comment lire les données d'une section Mach-O avec Objective-C sur les versions modernes de OS X/macOS : Crash de la lecture des octets de getsectbyname

La réponse décrite fonctionne. J'essaie d'implémenter la même chose avec Swift. Je n'arrive pas à le faire fonctionner.

J'ai ce qui suit dans "Other linker flags" : -Wl,-sectcreate,__LOCALIZATIONS,__base,en.lproj/Localizable.strings,-segprot,__LOCALIZATIONS,r,r .

Ce code Swift me permet d'obtenir un pointeur vers les données intégrées, jusqu'à ce que j'essaie d'exécuter le code en dehors de Xcode et que ASLR le casse :

var size: UInt = 0
let _localizationSection = getsectdata(
    "__LOCALIZATIONS",
    "__base",
    &size)

Pour contourner le problème de l'ASLR, selon la question et la réponse ci-dessus, et sur la base de mes propres tests, je devrais utiliser getsectiondata à la place. Cela fonctionne très bien en Objective-C, mais je n'ai pas de chance en Swift. Le texte suivant est la seule chose que j'ai réussi à faire passer au compilateur, mais il renvoie nil :

var size: UInt = 0
var header = _mh_execute_header
let localizationSection = getsectiondata(
    &header,
    "__LOCALIZATIONS",
    "__base",
    &size)

Est-ce que prendre une copie de _mh_execute_header le problème et y a-t-il un moyen de l'éviter ? J'ai besoin d'un UnsafePointer<mach_header_64> mais en utilisant &_mh_execute_header comme premier paramètre de getsectiondata provoque une erreur de compilation.

J'utilise Swift 3.0 et j'exécute mon code sous macOS 10.12.

3voto

Martin R Points 105727

La différence entre le code Objective-C lié

void *ptr = getsectiondata(&_mh_execute_header, ...);

et votre traduction Swift

var header = _mh_execute_header
let localizationSection = getsectiondata(&header, ...)

est que ce dernier transmet l'adresse d'un copie du monde _mh_execute_header à la fonction, et apparemment que n'est pas acceptée. Si vous modifiez le code Objective-C pour

struct mach_header_64 header = _mh_execute_header;
void *ptr = getsectiondata(&header, ...);

alors il échoue aussi (et s'est écrasé dans mon test).

Maintenant, le problème est que _mh_execute_header est exposé à Swift comme un constant :

public let _mh_execute_header: mach_header_64

et on ne peut pas prendre l'adresse d'une constante en Swift. Une solution de contournement contournement possible est de définir

#import <mach-o/ldsyms.h>
static const struct mach_header_64 *mhExecHeaderPtr = &_mh_execute_header;

dans le fichier d'en-tête de la passerelle, et ensuite l'utiliser comme

let localizationSection = getsectiondata(mhExecHeaderPtr, ...)

dans Swift.


Une autre option consiste à rechercher le symbole via dlopen / dlsym

import MachO

if let handle = dlopen(nil, RTLD_LAZY) {
    defer { dlclose(handle) }

    if let ptr = dlsym(handle, MH_EXECUTE_SYM) {
        let mhExecHeaderPtr = ptr.assumingMemoryBound(to: mach_header_64.self)

        var size: UInt = 0
        let localizationSection = getsectiondata(
            mhExecHeaderPtr,
            "__LOCALIZATIONS",
            "__base",
            &size)

        // ...
    }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X