[CCAPI] Créer un tool en C [Terminal/Invite de commande]

#42

restart system
Premium
Inscription
5 Juillet 2014
Messages
693
Réactions
315
Points
9 484
RGCoins
25
Bonsoir !
Je vais vous montrer comment coder un tool en C en commande (terminal/invite de commande)
Ce tutoriel s'adresse à ceux qui s'y connaisse déjà un peu en C, sinon ou pour apprendre le langage
Notre programme comportera les fonctions suivantes:
Code:
ConnectConsole
GetConsoleInfo
GetNumberOfConsoles
GetConnectionStatus
VshNotify
GetProcessList
GetProcessName
SetMemory

Commençons !

I - main

1) Ajoutez l'include windows.h
Code:
# include <windows.h>
2) Il faut créer une variable de type HINSTANCE ( qui se trouve dans windows.h ) cela permet de garder le pour notre programme. Dans cet exemple je vais utiliser CCAPI comme nom de variable
Code:
const HINSTANCE CCAPI = LoadLibrary("CCAPI.dll");
La fonction LoadLibrary va charger en mémoire la dll, qui elle sera pointée par CCAPI.
( Il vous faudra placer la dll dans le path de l'exécutable )

2a) La règle d'or ne jamais faire confiance à l'utilisateur
Code:
# include <windows.h>
# include <assert.h>

const HINSTANCE CCAPI = LoadLibrary("CCAPI.dll");
assert(CCAPI && "Move CCAPI.dll in executable path");
/* Le programme crash avec un message d'erreur à la ligne où le programme a crash &
le message d'erreur en question sera affiché sur la console si la dll n'est pas dans le même path que l'.exe */
3) Déclarer les prototypes des fonctions/struct/enum

Comme on peut le voir sur la doc d'Enstone

1460586968-eu9shoe.png

Il y a certains types de variable qui ne sont pas standard: ConsoleIdType / ConsoleId / ProcessName / ConsoleName etc..
En descendant plus bas, on voit qu'il donne aussi une doc pour ses propres types de variables
1460587694-1.png

1460587694-2.png

1460587694-3.png

Pour les besoins du programme nous auront besoin de
Code:
NotifyIcon
ConsoleName
ConsoleIp
ProcessName
u8
u32
u64
Voici donc leur définitions
Code:
typedef enum NotifyIcon
{
    NotifyInfo,
    NotifyCaution,
    NotifyFriend,
    NotifySlider,
    NotifyWrongWay,
    NotifyDialog,
    NotifyDalogShadow,
    NotifyText,
    NotifyPointer,
    NotifyGrab,
    NotifyHand,
    NotifyPen,
    NotifyFinger,
    NotifyArrow,
    NotifyArrowRight,
    NotifyProgress,
    NotifyTrophy1,
    NotifyTrophy2,
    NotifyTrophy3,
    NotifyTrophy4
} NotifyIcon;

typedef struct ConsoleName
{
   char value[256];
} ConsoleName;

typedef struct ConsoleIp
{
   char value[256];
} ConsoleIp;

typedef struct ProcessName
{
    char value[512];
} ProcessName;

typedef unsigned char           u8;
typedef unsigned int            u32;
typedef unsigned long long int  u64;
Comme je l'ai dit plus haut nous allons avoir besoin de quelques fonctions pour faire fonctionner le programme.
Voici leur prototype (ce sont des pointeurs sur fonction)
Code:
typedef int(*CCAPI_ConnectConsole)(const char *);
typedef int(*CCAPI_GetConsoleInfo)(int index, ConsoleName *, ConsoleIp *);
typedef int(*CCAPI_GetNumberOfConsoles)(void);
typedef int(*CCAPI_GetConnectionStatus)(int *);
typedef int(*CCAPI_VshNotify)(NotifyIcon, const char *);
typedef int(*CCAPI_GetProcessList)(u32 *, u32 *);
typedef int(*CCAPI_GetProcessName)(u32, ProcessName *);
typedef int(*CCAPI_SetMemory)(u32, u64, u32, const void *);
Libre à vous de choisir vos propres noms de variable si vous le souhaitez
Je vous conseille de séparer le code en plusieurs fichiers car tout dans un seul, vous risqueriez de vous y perdre très vite

II - Comment utiliser les pointeurs sur fonction

Je vais vous montrer comment les utiliser avec pour exemple CCAPI_ConnectConsole
Code:
CCAPI_ConnectConsole ConnectConsole = (CCAPI_ConnectConsole)GetProcAddress(CCAPI, "CCAPIConnectConsole");

Cela ne vous semble pas clair ? Je vous dois des explications.
Un pointeur sur fonction pointera sur l'adresse de la fonction qu'on lui aura transmit ou pour ceux qui préfèrent sur le point d'entrée de la fonction. GetProcAddress nous renvoi justement l'adresse de la fonction demandée en second paramètre, le premier paramètre sert à spécifier la dll que l'on va utiliser pour charger notre fonction

Ici donc vous l'aurez compris, la variable ConnectConsole pointera sur la fonction qu'elle va importer ici CCAPIConnectConsole

On s'assure que la fonction a bel et bien été chargée.​
Code:
CCAPI_ConnectConsole ConnectConsole = (CCAPI_ConnectConsole)GetProcAddress(CCAPI, "CCAPIConnectConsole");
assert(ConnectConsole && "Can't load ConnectConsole function from CCAPI.dll");
Une fois toutes les précautions prises, utilisons la fonction:
Code:
if (ConnectConsole(ip) == CCAPI_OK)
    printf("Connected ..\n");
1460901798-15.png

Une fois que vous aurez terminé d'utiliser la librairie, penser à la décharger avec la fonction suivante
Code:
FreeLibrary(CCAPI);

Vous savez maintenant comment charger une fonction depuis une dll​

III - Afficher les adresses IP

Pour que cela soit plus propre je propose qu'on affiche les adresses IP présentes dans CC

1460756909-15.png


Pour ce faire je vais utiliser une liste chainée pour certains cette étape paraitra compliqué alors je vous invite à sauter cette étape et demander l'adresse IP à l'utilisateur directement, plus précisément ce sera une .

Voici le prototype de la liste​
Code:
struct ConsoleInfoList {
  size_t count;
  ConsoleInfo *head;
  ConsoleInfo *tail;
};

struct ConsoleInfo {
  char *name;
  char *ip;
  ConsoleInfo *next;
  ConsoleInfo *prev;
};

Vous l'aurez compris, le champ name sera pour le nom de la PS3, et le champ ip pour l'IP de la PS3.
Ici on sépare la liste de son contenu, la tête pointera sur ConsoleInfo et le pied pointera aussi sur ConsoleInfo.

Maintenant, je vous propose de créer une fonction du style
Code:
ConsoleInfoList     *ShowIPList(const HINSTANCE CCAPI);

Où l'on va avoir besoin de CCAPIGetConsoleInfo et CCAPIGetNumberOfConsoles
Code:
ConsoleInfoList     *ShowIPList(const HINSTANCE CCAPI)
{
    CCAPI_GetConsoleInfo GetConsoleInfo = (CCAPI_GetConsoleInfo)GetProcAddress(CCAPI, "CCAPIGetConsoleInfo");
    assert(GetConsoleInfo && "Can't load GetConsoleInfo function from CCAPI.dll");

    CCAPI_GetNumberOfConsoles GetNumberOfConsoles = (CCAPI_GetNumberOfConsoles)GetProcAddress(CCAPI, "CCAPIGetNumberOfConsoles");
    assert(GetNumberOfConsoles && "Can't load GetNumberOfConsoles function from CCAPI.dll");
..
À noter à chaque fois le important

Maintenant on va créer une nouvelle liste de type ConsoleInfoList
Code:
ConsoleInfoList *cil = CIL_new();
Code:
ConsoleInfoList *CIL_new(void);
Je le répète encore une fois, n'hésiter pas à séparer votre code en plusieurs fichiers

La fonction CIL_new nous permettant de créer un espace mémoire pour accueillir notre liste et d'initialiser ses éléments​
Code:
ConsoleInfoList     *CIL_new(void)
{
    ConsoleInfoList    *list;

    if ((list = malloc(sizeof(ConsoleInfoList))))
    {
        list->count = 0;
        list->head = NULL;
        list->tail = NULL;
    }
    return (list);
}
Je pense qu'il n'y a rien de particulier à expliquer ici ..

Si vous suivez correctement, votre fonction devrait ressembler à cela pour le moment​
Code:
ConsoleInfoList     *ShowIPList(const HINSTANCE CCAPI)
{
    CCAPI_GetConsoleInfo GetConsoleInfo = (CCAPI_GetConsoleInfo)GetProcAddress(CCAPI, "CCAPIGetConsoleInfo");
    assert(GetConsoleInfo && "Can't load GetConsoleInfo function from CCAPI.dll");

    CCAPI_GetNumberOfConsoles GetNumberOfConsoles = (CCAPI_GetNumberOfConsoles)GetProcAddress(CCAPI, "CCAPIGetNumberOfConsoles");
    assert(GetNumberOfConsoles && "Can't load GetNumberOfConsoles function from CCAPI.dll");

    ConsoleInfoList *cil = CIL_new();
    if (!cil)
        return (NULL);
..
Maintenant, on va ajouter une console dans notre liste, pour la récupérer c'est simple, on utilise la fonction GetConsoleInfo, et en plus Enstone donne un exemple, c'est parfait sa nous facilite la tâche et, on va de suite s'en servir​
1460759356-15.png
Code:
ConsoleInfoList     *ShowIPList(const HINSTANCE CCAPI)
{
    CCAPI_GetConsoleInfo GetConsoleInfo = (CCAPI_GetConsoleInfo)GetProcAddress(CCAPI, "CCAPIGetConsoleInfo");
    assert(GetConsoleInfo && "Can't load GetConsoleInfo function from CCAPI.dll");

    CCAPI_GetNumberOfConsoles GetNumberOfConsoles = (CCAPI_GetNumberOfConsoles)GetProcAddress(CCAPI, "CCAPIGetNumberOfConsoles");
    assert(GetNumberOfConsoles && "Can't load GetNumberOfConsoles function from CCAPI.dll");

    ConsoleInfoList *cil = CIL_new();
    if (!cil)
        return (NULL);

    ConsoleName name;
    ConsoleIp   ip;
    for (int i = 0; i < GetNumberOfConsoles(); ++i)
    {
        GetConsoleInfo(i, &name, &ip);
        cil = CIL_append(cil, name.value, ip.value);
    }
..
Notre fonction CIL_append nous permettra d'ajouter un " élément " en fin de liste, enfin vous comprendrez mieux après avoir vu le code​
Code:
ConsoleInfoList     *CIL_append(ConsoleInfoList *list, const char *name, const char *ip)
{
    if (CIL_is_empty(list))
    {
        list->head = list->tail = CI_new(name, ip, NULL, NULL);
    }
    else
    {
        ConsoleInfo *new = CI_new(name, ip, list->tail, NULL);
        CI_set_next(CIL_get_tail(list), new);
        CIL_set_tail(list, new);
    }
    list->count++;
    return (list);
}
Dans un premier temps, on vérifie que la liste n'est pas vide​
Code:
# include <stdbool.h>

bool                CIL_is_empty(const ConsoleInfoList *list)
{
    return (list->count == 0);
}
Si elle est vide alors, elle exécute la fonction suivante pour la tête de la liste et le pied de la liste et attribuera le nom, l'ip, son prochain élément et son élément précèdent
Code:
ConsoleInfo         *CI_new(const char *name, const char *ip, ConsoleInfo *prev, ConsoleInfo *next)
{
    ConsoleInfo *list;
    if ((list = malloc(sizeof(ConsoleInfo))))
    {
        list->name  = strdup(name);
        list->ip    = strdup(ip);
        list->prev  = !prev ? NULL : prev;
        list->next  = !next ? NULL : next;
    }
    return (list);
}
Code:
char                *strdup(const char *s1)
{
    const size_t len    = strlen(s1) + 1;
    char        *p      = malloc(len);

    return (p ? memcpy(p, s1, len) : NULL);
}

Ces fonctions sont très basics et je pense pas non plus qu'il y est quelque chose à dire
Dans le cas contraire​
Code:
else
{
    ConsoleInfo *new = CI_new(name, ip, list->tail, NULL);
    CI_set_next(CIL_get_tail(list), new);
    CIL_set_tail(list, new);
}
Code:
ConsoleInfo         *CI_set_next(ConsoleInfo *list, ConsoleInfo *list_next)
{
    list->next = list_next;
    return (list);
}
ConsoleInfo         *CIL_get_tail(const ConsoleInfoList *list)
{
    return (list->tail);
}

ConsoleInfoList     *CIL_set_tail(ConsoleInfoList *list, ConsoleInfo *list_tail)
{
    list->tail = list_tail;
    return (list);
}
Explications
  • Code:
    ConsoleInfo *new = CI_new(name, ip, list->tail, NULL);
pointera vers le dernier élément de la liste
  • Code:
    CI_set_next(CIL_get_tail(list), new);
(dernier élément de la liste) sera pointé sur le nouvel élément
  • Code:
    CIL_set_tail(list, new);
La fin de la liste sera pointé vers le nouvel élément

Ceci pourrait donc très bien se traduire sans fonction comme ça​
Code:
else
{
    ConsoleInfo *new = CI_new(name, ip, list->tail, NULL);
    list->tail->next = new;
    list->tail = new;
}
Ensuite, on augmente de 1 le nombre d'éléments dans notre liste et, retourne cette dernière​
Code:
list->count++;
return (list);
Voici une image pour aider à comprendre comment on pourrait représenter la liste
1460913764-16.png

Dans la fonction ShowIPList, il nous reste plus qu'à afficher les adresses IP et retourner la list​
Code:
for (ConsoleInfo *ci = CIL_get_head(cil); ci; ci = CI_get_next(ci))
        CI_print(ci);

printf("Select an IP Adress (1 .. %zu)\n", cil->count);
return (cil);
Code:
ConsoleInfo         *CIL_get_head(const ConsoleInfoList *list)
{
    return (list->head);
}

ConsoleInfo         *CI_get_next(const ConsoleInfo *list)
{
    return (list->next);
}

void                CI_print(const ConsoleInfo *list)
{
    printf("Nom: %s\tIP: %s\n", list->name, list->ip);
}
Encore une fois, cela aurait pu se traduire sans fonction comme ça​
Code:
for (ConsoleInfo *ci = cil->head; ci; ci = ci->next)
Voilà ! Notre fonction ShowIPList est enfin terminé !

IV - Se connecter

Maintenant que nous avons récupérés les adresses IPs contenues dans CC, utilisons-les !
Je vous propose de créer une fonction qui contiendra pour l'instant​
Code:
int                 ConnectConsole(const HINSTANCE CCAPI)
{
    ConsoleInfoList *cil    = ShowIPList(CCAPI);
    const char      *ip     = GetIPConnect(cil);
..
Code:
char  *GetIPConnect(const ConsoleInfoList *cil);
GetIPConnect nous retournera l'adresse IP sélectionner par l'utilisateur​
Code:
char                *GetIPConnect(const ConsoleInfoList *cil)
{
    ConsoleInfoList *tmp = (ConsoleInfoList *)cil;
    size_t c;
    while (!((c = getchar()) > '0' && c - '0' <= tmp->count))
        ;
    c -= '0';
    tmp->head = GetIPCIL(tmp, c);
    printf("Console selected: %zu [%s - %s]\n", c, tmp->head->name, tmp->head->ip);

    clean_stdin();
    return (tmp->head->ip);
}
Ici, rien de très compliqué sauf si vous ne connaissez pas la fonction , la fonction GetIPCIL nous retournera l'index (ici c) de l'IP sélectionner​
Code:
ConsoleInfo         *GetIPCIL(const ConsoleInfoList *cil, const size_t c)
{
    ConsoleInfoList *tmp = (ConsoleInfoList *)cil;
    if (c == 1)
        return (tmp->head);
    if (c == tmp->count)
        return (tmp->tail);
    if (c > (tmp->count / 2) + 1)
    {
        for (unsigned int i = 0; i < (tmp->count - c); ++i)
            tmp->tail = tmp->tail->prev;
        return (tmp->tail);
    }
    for (unsigned int i = 1; i < c; ++i)
        tmp->head = tmp->head->next;
    return (tmp->head);
}
Code assez banal, si l'index est 1 alors on renvoi directement la tête sinon si l'index est égal au nombre d'éléments de la liste alors renvoi le pied
Sinon
, si l'index est supérieur à la moitié alors on va partir de la fin pour ne pas parcourir les premiers éléments qui ne feront que retardés(pas énorme) le programme sinon on par du début.

La fonction clean_stdin nous permet de
Code:
void                clean_stdin(void)
{
    int c;
    while ((c = getchar()) != EOF && c != '\n');
}
Il nous reste plus qu'à retourner l'adresse IP maintenant : )​
Code:
return (tmp->head->ip);
Maintenant que nous avons l'adresse IP sélectionner par l'utilisateur, nous allons pouvoir libérer notre liste chainée de la mémoire​
Code:
int                 ConnectConsole(const HINSTANCE CCAPI)
{
    ConsoleInfoList *cil    = ShowIPList(CCAPI);
    const char      *ip     = GetIPConnect(cil);

    CIL_del(&cil);
..
Code:
void                CIL_del(ConsoleInfoList **list)
{
    ConsoleInfo *tmp_list = (*list)->tail;

    while (tmp_list)
    {
        ConsoleInfo *tmp_del = tmp_list;
        tmp_list = tmp_list->prev;
        free(tmp_del);
    }
    memdel((void **)list);
}
Code:
void                memdel(void **ap)
{
    free(*ap);
    *ap = NULL;
}
Ici nous allons créer une liste de type ConsoleInfo qui pointera sur list->tail, on part donc du partir du pied car rappelez-vous nous avons modifié head quand nous avons retourné l'adresse IP (sauf si l'utilisateur a choisit 1 ou nb_element_list (count))
Tant que tmp_list n'est pas égal à NULL ->
tmp_del pointera sur l'élément qui sera libéré
tmp_list sera égal à son prochain
On libère l'élément
Si tmp_list est égal à NULL ->
On libère la liste
et on l'a met à NULL car la liste ne sera plus utilisée ! (grâce à memdel)
Notre liste est maintenant libérée !
Retour à ConnectConsole, après avoir libérée la liste, connectons-nous à la PS3 !​
Code:
int                 ConnectConsole(const HINSTANCE CCAPI)
{
    ConsoleInfoList *cil    = ShowIPList(CCAPI);
    const char      *ip     = GetIPConnect(cil);

    CIL_del(&cil);
    CCAPI_ConnectConsole ConnectConsole = (CCAPI_ConnectConsole)GetProcAddress(CCAPI, "CCAPIConnectConsole");
    assert(ConnectConsole && "Can't load ConnectConsole function from CCAPI.dll");

    CCAPI_VshNotify Notify = (CCAPI_VshNotify)GetProcAddress(CCAPI, "CCAPIVshNotify");
    assert(Notify && "Can't load Notify function from CCAPI.dll");

    CCAPI_GetConnectionStatus GetConnectionStatus = (CCAPI_GetConnectionStatus)GetProcAddress(CCAPI, "CCAPIGetConnectionStatus");
    assert(GetConnectionStatus && "Can't load GetConnectionStatus function from CCAPI.dll");

    if (ConnectConsole(ip) == CCAPI_OK)
        Notify(NotifyCaution, "Connected!");
    int status;
    GetConnectionStatus(&status);
    printf("Status connection: %s\n", status ? "Connected" : "Not connected");
    return (!status);
}
J'pense que vous avez tout compris ici à part sans doute
Code:
return (!status);
Explications
Si la console a réussi à se connecter alors status sera > 0, si je fais !status cela me retournera 0 si status != 0, pour pouvoir tester dans le main avec CCAPI_OK, j'aurais très bien pu aussi directement tester avec !=
Notre fonction ConnectConsole est maintenant terminé, votre main devrait ressembler à ça​
Code:
/*
* * Vos includes
*/
# include "main.h"
# include "ccapi.h"

int     main(void)
{
    const HINSTANCE CCAPI = LoadLibrary("CCAPI.dll");
    assert(CCAPI && "Move CCAPI.dll in executable path");

    const int ret_cc = ConnectConsole(CCAPI);
    assert(ret_cc == CCAPI_OK && "Can't connect to PS3");
..

V - Attacher le processus

Alors sur cette fonction, j'ai tout simplement copié/collé la fonction d'iMCSx en C#
1460924898-15.png

Voici comment je l'ai codé en C​
Code:
char                *GetProcessName(const HINSTANCE CCAPI, u32 pid)
{
    CCAPI_GetProcessName GetProcessName = (CCAPI_GetProcessName)GetProcAddress(CCAPI, "CCAPIGetProcessName");
    assert(GetProcessName && "Can't load GetProcessName function from CCAPI.dll");

    ProcessName name;
    if (GetProcessName(pid, &name) == CCAPI_OK)
        return (strdup(name.value));
    return (NULL);
}

bool                GetProcessList(const HINSTANCE CCAPI, u32 **pids, u32 *npid)
{
    CCAPI_GetProcessList GetProcessList = (CCAPI_GetProcessList)GetProcAddress(CCAPI, "CCAPIGetProcessList");
    assert(GetProcessList && "Can't load GetProcessList function from CCAPI.dll");

    GetProcessList(npid, 0);

    *pids = (u32 *)malloc(*npid * sizeof(u32));
    if (*pids)
    {
        if (GetProcessList(npid, *pids) == CCAPI_OK)
            return (true);
    }
    return (false);
}

bool                AttachProcess(const HINSTANCE CCAPI, u32 *pid)
{
    size_t  count;
    u32     *pids;
    char    *pname;

    bool result = GetProcessList(CCAPI, &pids, &count);
    if (!result)
        return (result);
    for (unsigned int i = 0; i < count; ++i)
    {
        if ((pname = GetProcessName(CCAPI, pids[i])))
        {
            if (!strstr(pname, "flash"))
            {
                *pid = pids[i];
                break;
            }
            else
                result = false;
        }
    }
    memdel((void **)&pids);
    return (result);
}
À partir de maintenant j'expliquerai donc beaucoup moins les choses voir pas du tout, là encore tout est expliqué sur la

Votre main devrait maintenant contenir une fonction de + : AttachProcess
Code:
int     main(void)
{
    const HINSTANCE CCAPI = LoadLibrary("CCAPI.dll");
    assert(CCAPI && "Move CCAPI.dll in executable path");

    const int ret_cc = ConnectConsole(CCAPI);
    assert(ret_cc == CCAPI_OK && "Can't connect to PS3");

    u32 pid;
    const bool ret_ap = AttachProcess(CCAPI, &pid);
    assert(ret_ap != CCAPI_OK && "Can't attach default process game");
..
VI - SetMemory

La fonction SetMemory tout bête !
Code:
int                 SetMemory(const HINSTANCE CCAPI, u32 pid, u64 offset, u32 size, const void *data)
{
    CCAPI_SetMemory SetMemory = (CCAPI_SetMemory)GetProcAddress(CCAPI, "CCAPISetMemory");
    assert(SetMemory && "Can't load SetMemory function from CCAPI.dll");

    return (SetMemory(pid, offset, size, data));
}

À partir de maintenant, vous pouvez changer votre prestige, stats vous faire un unlock all etc.. Enstone vous montre un (Rien ne vous empêche par la suite de programmer en fenêtre)

Fin
Voilà, le tuto s'arrête si tu as des questions n'hésite pas à commenter (no mp stp) et n'oublies pas de free la dll avec FreeLibrary : )

Voici ma source complète sur github qui contiendra un peu + de fonctions

1460933129-15.png


Crédits: iMCSx x Enstone x OpenClassroom x Stackoverflow
Certains diront " ctro compliké pr cke c ", c'est vrai mais c'est pour s'amuser ; )
 
Dernière édition:
Bonsoir !
Je vais vous montrer comment coder un tool en C en commande (terminal/invite de commande)
Ce tutoriel s'adresse à ceux qui s'y connaisse déjà un peu en C, sinon ou pour apprendre le langage
Notre programme comportera les fonctions suivantes:
Code:
ConnectConsole
GetConsoleInfo
GetNumberOfConsoles
GetConnectionStatus
VshNotify
GetProcessList
GetProcessName
SetMemory

Commençons !

I - main

1) Ajoutez l'include windows.h
Code:
# include <windows.h>
2) Il faut créer une variable de type HINSTANCE ( qui se trouve dans windows.h ) cela permet de garder le pour notre programme. Dans cet exemple je vais utiliser CCAPI comme nom de variable
Code:
const HINSTANCE CCAPI = LoadLibrary("CCAPI.dll");
La fonction LoadLibrary va charger en mémoire la dll, qui elle sera pointée par CCAPI.
( Il vous faudra placer la dll dans le path de l'exécutable )

2a) La règle d'or ne jamais faire confiance à l'utilisateur
Code:
# include <windows.h>
# include <assert.h>

const HINSTANCE CCAPI = LoadLibrary("CCAPI.dll");
assert(CCAPI && "Move CCAPI.dll in executable path");
/* Le programme crash avec un message d'erreur à la ligne où le programme a crash &
le message d'erreur en question sera affiché sur la console si la dll n'est pas dans le même path que l'.exe */
3) Déclarer les prototypes des fonctions/struct/enum

Comme on peut le voir sur la doc d'Enstone

1460586968-eu9shoe.png

Il y a certains types de variable qui ne sont pas standard: ConsoleIdType / ConsoleId / ProcessName / ConsoleName etc..
En descendant plus bas, on voit qu'il donne aussi une doc pour ses propres types de variables
1460587694-1.png

1460587694-2.png

1460587694-3.png

Pour les besoins du programme nous auront besoin de
Code:
NotifyIcon
ConsoleName
ConsoleIp
ProcessName
u8
u32
u64
Voici donc leur définitions
Code:
typedef enum NotifyIcon
{
    NotifyInfo,
    NotifyCaution,
    NotifyFriend,
    NotifySlider,
    NotifyWrongWay,
    NotifyDialog,
    NotifyDalogShadow,
    NotifyText,
    NotifyPointer,
    NotifyGrab,
    NotifyHand,
    NotifyPen,
    NotifyFinger,
    NotifyArrow,
    NotifyArrowRight,
    NotifyProgress,
    NotifyTrophy1,
    NotifyTrophy2,
    NotifyTrophy3,
    NotifyTrophy4
} NotifyIcon;

typedef struct ConsoleName
{
   char value[256];
} ConsoleName;

typedef struct ConsoleIp
{
   char value[256];
} ConsoleIp;

typedef struct ProcessName
{
    char value[512];
} ProcessName;

typedef unsigned char           u8;
typedef unsigned int            u32;
typedef unsigned long long int  u64;
Comme je l'ai dit plus haut nous allons avoir besoin de quelques fonctions pour faire fonctionner le programme.
Voici leur prototype (ce sont des pointeurs sur fonction)
Code:
typedef int(*CCAPI_ConnectConsole)(const char *);
typedef int(*CCAPI_GetConsoleInfo)(int index, ConsoleName *, ConsoleIp *);
typedef int(*CCAPI_GetNumberOfConsoles)(void);
typedef int(*CCAPI_GetConnectionStatus)(int *);
typedef int(*CCAPI_VshNotify)(NotifyIcon, const char *);
typedef int(*CCAPI_GetProcessList)(u32 *, u32 *);
typedef int(*CCAPI_GetProcessName)(u32, ProcessName *);
typedef int(*CCAPI_SetMemory)(u32, u64, u32, const void *);
Libre à vous de choisir vos propres noms de variable si vous le souhaitez
Je vous conseille de séparer le code en plusieurs fichiers car tout dans un seul, vous risqueriez de vous y perdre très vite

II - Comment utiliser les pointeurs sur fonction

Je vais vous montrer comment les utiliser avec pour exemple CCAPI_ConnectConsole
Code:
CCAPI_ConnectConsole ConnectConsole = (CCAPI_ConnectConsole)GetProcAddress(CCAPI, "CCAPIConnectConsole");

Cela vous semble pas clair ? Je vous dois des explications.
Un pointeur sur fonction pointera sur l'adresse de la fonction qu'on lui aura transmit ou pour ceux qui préfèrent sur le point d'entrée de la fonction. GetProcAddress nous renvoi justement l'adresse de la fonction demandée en second paramètre, le premier paramètre sert à spécifier la dll que l'on va utiliser pour charger notre fonction

Ici donc vous l'aurez compris, la variable ConnectConsole pointera sur la fonction qu'elle va importer ici CCAPIConnectConsole

On s'assure que la fonction a bel et bien été chargée.​
Code:
CCAPI_ConnectConsole ConnectConsole = (CCAPI_ConnectConsole)GetProcAddress(CCAPI, "CCAPIConnectConsole");
assert(ConnectConsole && "Can't load ConnectConsole function from CCAPI.dll");
Une fois toutes les précautions prises, utilisons la fonction:
Code:
if (ConnectConsole(ip) == CCAPI_OK)
    printf("Connected ..\n");
1460901798-15.png

Une fois que vous aurez terminé d'utiliser la librairie, penser à la décharger avec la fonction suivante
Code:
FreeLibrary(CCAPI);

Vous savez maintenant comment charger une fonction depuis une dll​

III - Afficher les adresses IP

Pour que cela soit plus propre je propose qu'on affiche les adresses IP présentes dans CC

1460756909-15.png


Pour ce faire je vais utiliser une liste chainée pour certains cette étape paraitra compliqué alors je vous invite à sauter cette étape et demander l'adresse IP à l'utilisateur directement, plus précisément ce sera une .

Voici le prototype de la liste​
Code:
struct ConsoleInfoList {
  size_t count;
  ConsoleInfo *head;
  ConsoleInfo *tail;
};

struct ConsoleInfo {
  char *name;
  char *ip;
  ConsoleInfo *next;
  ConsoleInfo *prev;
};

Vous l'aurez compris, le champ name sera pour le nom de la PS3, et le champ ip pour l'IP de la PS3.
Ici on sépare la liste de son contenu, la tête pointera sur ConsoleInfo et le pied pointera aussi sur ConsoleInfo.

Maintenant, je vous propose de créer une fonction du style
Code:
ConsoleInfoList     *ShowIPList(const HINSTANCE CCAPI);

Où l'on va avoir besoin de CCAPIGetConsoleInfo et CCAPIGetNumberOfConsoles
Code:
ConsoleInfoList     *ShowIPList(const HINSTANCE CCAPI)
{
    CCAPI_GetConsoleInfo GetConsoleInfo = (CCAPI_GetConsoleInfo)GetProcAddress(CCAPI, "CCAPIGetConsoleInfo");
    assert(GetConsoleInfo && "Can't load GetConsoleInfo function from CCAPI.dll");

    CCAPI_GetNumberOfConsoles GetNumberOfConsoles = (CCAPI_GetNumberOfConsoles)GetProcAddress(CCAPI, "CCAPIGetNumberOfConsoles");
    assert(GetNumberOfConsoles && "Can't load GetNumberOfConsoles function from CCAPI.dll");
..
À noter à chaque fois le important

Maintenant on va créer une nouvelle liste de type ConsoleInfoList
Code:
ConsoleInfoList *cil = CIL_new();
Code:
ConsoleInfoList *CIL_new(void);
Je le répète encore une fois, n'hésiter pas à séparer votre code en plusieurs fichiers

La fonction CIL_new nous permettant de créer un espace mémoire pour accueillir notre liste et d'initialiser ses éléments​
Code:
ConsoleInfoList     *CIL_new(void)
{
    ConsoleInfoList    *list;

    if ((list = malloc(sizeof(ConsoleInfoList))))
    {
        list->count = 0;
        list->head = NULL;
        list->tail = NULL;
    }
    return (list);
}
Je pense qu'il n'y a rien de particulier à expliquer ici ..

Si vous suivez correctement, votre fonction devrait ressembler à cela pour le moment​
Code:
ConsoleInfoList     *ShowIPList(const HINSTANCE CCAPI)
{
    CCAPI_GetConsoleInfo GetConsoleInfo = (CCAPI_GetConsoleInfo)GetProcAddress(CCAPI, "CCAPIGetConsoleInfo");
    assert(GetConsoleInfo && "Can't load GetConsoleInfo function from CCAPI.dll");

    CCAPI_GetNumberOfConsoles GetNumberOfConsoles = (CCAPI_GetNumberOfConsoles)GetProcAddress(CCAPI, "CCAPIGetNumberOfConsoles");
    assert(GetNumberOfConsoles && "Can't load GetNumberOfConsoles function from CCAPI.dll");

    ConsoleInfoList *cil = CIL_new();
    if (!cil)
        return (NULL);
..
Maintenant, on va ajouter une console dans notre liste, pour la récupérer c'est simple, on utilise la fonction GetConsoleInfo, et en plus Enstone donne un exemple, c'est parfait sa nous facilite la tâche et, on va de suite s'en servir​
1460759356-15.png
Code:
ConsoleInfoList     *ShowIPList(const HINSTANCE CCAPI)
{
    CCAPI_GetConsoleInfo GetConsoleInfo = (CCAPI_GetConsoleInfo)GetProcAddress(CCAPI, "CCAPIGetConsoleInfo");
    assert(GetConsoleInfo && "Can't load GetConsoleInfo function from CCAPI.dll");

    CCAPI_GetNumberOfConsoles GetNumberOfConsoles = (CCAPI_GetNumberOfConsoles)GetProcAddress(CCAPI, "CCAPIGetNumberOfConsoles");
    assert(GetNumberOfConsoles && "Can't load GetNumberOfConsoles function from CCAPI.dll");

    ConsoleInfoList *cil = CIL_new();
    if (!cil)
        return (NULL);

    ConsoleName name;
    ConsoleIp   ip;
    for (int i = 0; i < GetNumberOfConsoles(); ++i)
    {
        GetConsoleInfo(i, &name, &ip);
        cil = CIL_append(cil, name.value, ip.value);
    }
..
Notre fonction CIL_append nous permettra d'ajouter un " élément " en fin de liste, enfin vous comprendrez mieux après avoir vu le code​
Code:
ConsoleInfoList     *CIL_append(ConsoleInfoList *list, const char *name, const char *ip)
{
    if (CIL_is_empty(list))
    {
        list->head = list->tail = CI_new(name, ip, NULL, NULL);
    }
    else
    {
        ConsoleInfo *new = CI_new(name, ip, list->tail, NULL);
        CI_set_next(CIL_get_tail(list), new);
        CIL_set_tail(list, new);
    }
    list->count++;
    return (list);
}
Dans un premier temps, on vérifie que la liste n'est pas vide​
Code:
# include <stdbool.h>

bool                CIL_is_empty(const ConsoleInfoList *list)
{
    return (list->count == 0);
}
Si elle est vide alors, elle exécute la fonction suivante pour la tête de la liste et le pied de la liste et attribuera le nom, l'ip, son prochain élément et son élément précèdent
Code:
ConsoleInfo         *CI_new(const char *name, const char *ip, ConsoleInfo *prev, ConsoleInfo *next)
{
    ConsoleInfo *list;
    if ((list = malloc(sizeof(ConsoleInfo))))
    {
        list->name  = strdup(name);
        list->ip    = strdup(ip);
        list->prev  = !prev ? NULL : prev;
        list->next  = !next ? NULL : next;
    }
    return (list);
}
Code:
char                *strdup(const char *s1)
{
    const size_t len    = strlen(s1) + 1;
    char        *p      = malloc(len);

    return (p ? memcpy(p, s1, len) : NULL);
}

Ces fonctions sont très basics et je pense pas non plus qu'il y est quelque chose à dire
Dans le cas contraire​
Code:
else
{
    ConsoleInfo *new = CI_new(name, ip, list->tail, NULL);
    CI_set_next(CIL_get_tail(list), new);
    CIL_set_tail(list, new);
}
Code:
ConsoleInfo         *CI_set_next(ConsoleInfo *list, ConsoleInfo *list_next)
{
    list->next = list_next;
    return (list);
}
ConsoleInfo         *CIL_get_tail(const ConsoleInfoList *list)
{
    return (list->tail);
}

ConsoleInfoList     *CIL_set_tail(ConsoleInfoList *list, ConsoleInfo *list_tail)
{
    list->tail = list_tail;
    return (list);
}
Explications
  • Code:
    ConsoleInfo *new = CI_new(name, ip, list->tail, NULL);
pointera vers le dernier élément de la liste
  • Code:
    CI_set_next(CIL_get_tail(list), new);
(dernier élément de la liste) sera pointé sur le nouvel élément
  • Code:
    CIL_set_tail(list, new);
La fin de la liste sera pointé vers le nouvel élément

Ceci pourrait donc très bien se traduire sans fonction comme ça​
Code:
else
{
    ConsoleInfo *new = CI_new(name, ip, list->tail, NULL);
    list->tail->next = new;
    list->tail = new;
}
Ensuite, on augmente de 1 le nombre d'éléments dans notre liste et, retourne cette dernière​
Code:
list->count++;
return (list);
Voici une image pour aider à comprendre comment on pourrait représenter la liste
1460913764-16.png

Dans la fonction ShowIPList, il nous reste plus qu'à afficher les adresses IP et retourner la list​
Code:
for (ConsoleInfo *ci = CIL_get_head(cil); ci; ci = CI_get_next(ci))
        CI_print(ci);

printf("Select an IP Adress (1 .. %zu)\n", cil->count);
return (cil);
Code:
ConsoleInfo         *CIL_get_head(const ConsoleInfoList *list)
{
    return (list->head);
}

ConsoleInfo         *CI_get_next(const ConsoleInfo *list)
{
    return (list->next);
}

void                CI_print(const ConsoleInfo *list)
{
    printf("Nom: %s\tIP: %s\n", list->name, list->ip);
}
Encore une fois, cela aurait pu se traduire sans fonction comme ça​
Code:
for (ConsoleInfo *ci = cil->head; ci; ci = ci->next)
Voilà ! Notre fonction ShowIPList est enfin terminé !

IV - Se connecter

Maintenant que nous avons récupérés les adresses IPs contenues dans CC, utilisons-les !
Je vous propose de créer une fonction qui contiendra pour l'instant​
Code:
int                 ConnectConsole(const HINSTANCE CCAPI)
{
    ConsoleInfoList *cil    = ShowIPList(CCAPI);
    const char      *ip     = GetIPConnect(cil);
..
Code:
char  *GetIPConnect(const ConsoleInfoList *cil);
GetIPConnect nous retournera l'adresse IP sélectionner par l'utilisateur​
Code:
char                *GetIPConnect(const ConsoleInfoList *cil)
{
    ConsoleInfoList *tmp = (ConsoleInfoList *)cil;
    size_t c;
    while (!((c = getchar()) > '0' && c - '0' <= tmp->count))
        ;
    c -= '0';
    tmp->head = GetIPCIL(tmp, c);
    printf("Console selected: %zu [%s - %s]\n", c, tmp->head->name, tmp->head->ip);

    clean_stdin();
    return (tmp->head->ip);
}
Ici, rien de très compliqué sauf si vous ne connaissez pas la fonction , la fonction GetIPCIL nous retournera l'index (ici c) de l'IP sélectionner​
Code:
ConsoleInfo         *GetIPCIL(const ConsoleInfoList *cil, const size_t c)
{
    ConsoleInfoList *tmp = (ConsoleInfoList *)cil;
    if (c == 1)
        return (tmp->head);
    if (c == tmp->count)
        return (tmp->tail);
    if (c > (tmp->count / 2) + 1)
    {
        for (unsigned int i = 0; i < (tmp->count - c); ++i)
            tmp->tail = tmp->tail->prev;
        return (tmp->tail);
    }
    for (unsigned int i = 1; i < c; ++i)
        tmp->head = tmp->head->next;
    return (tmp->head);
}
Code assez banal, si l'index est 1 alors on renvoi directement la tête sinon si l'index est égal au nombre d'éléments de la liste alors renvoi le pied
Sinon
, si l'index est supérieur à la moitié alors on va partir de la fin pour ne pas parcourir les premiers éléments qui ne feront que retardés(pas énorme) le programme sinon on par du début.

La fonction clean_stdin nous permet de
Code:
void                clean_stdin(void)
{
    int c;
    while ((c = getchar()) != EOF && c != '\n');
}
Il nous reste plus qu'à retourner l'adresse IP maintenant : )​
Code:
return (tmp->head->ip);
Maintenant que nous avons l'adresse IP sélectionner par l'utilisateur, nous allons pouvoir libérer notre liste chainée de la mémoire​
Code:
int                 ConnectConsole(const HINSTANCE CCAPI)
{
    ConsoleInfoList *cil    = ShowIPList(CCAPI);
    const char      *ip     = GetIPConnect(cil);

    CIL_del(&cil);
..
Code:
void                CIL_del(ConsoleInfoList **list)
{
    ConsoleInfo *tmp_list = (*list)->tail;

    while (tmp_list)
    {
        ConsoleInfo *tmp_del = tmp_list;
        tmp_list = tmp_list->prev;
        free(tmp_del);
    }
    memdel((void **)list);
}
Code:
void                memdel(void **ap)
{
    free(*ap);
    *ap = NULL;
}
Ici nous allons créer une liste de type ConsoleInfo qui pointera sur list->tail, on part donc du partir du pied car rappelez-vous nous avons modifié head quand nous avons retourné l'adresse IP (sauf si l'utilisateur a choisit 1 ou nb_element_list (count))
Tant que tmp_list n'est pas égal à NULL ->
tmp_del pointera sur l'élément qui sera libéré
tmp_list sera égal à son prochain
On libère l'élément
Si tmp_list est égal à NULL ->
On libère la liste
et on l'a met à NULL car la liste ne sera plus utilisée ! (grâce à memdel)
Notre liste est maintenant libérée !
Retour à ConnectConsole, après avoir libérée la liste, connectons-nous à la PS3 !​
Code:
int                 ConnectConsole(const HINSTANCE CCAPI)
{
    ConsoleInfoList *cil    = ShowIPList(CCAPI);
    const char      *ip     = GetIPConnect(cil);

    CIL_del(&cil);
    CCAPI_ConnectConsole ConnectConsole = (CCAPI_ConnectConsole)GetProcAddress(CCAPI, "CCAPIConnectConsole");
    assert(ConnectConsole && "Can't load ConnectConsole function from CCAPI.dll");

    CCAPI_VshNotify Notify = (CCAPI_VshNotify)GetProcAddress(CCAPI, "CCAPIVshNotify");
    assert(Notify && "Can't load Notify function from CCAPI.dll");

    CCAPI_GetConnectionStatus GetConnectionStatus = (CCAPI_GetConnectionStatus)GetProcAddress(CCAPI, "CCAPIGetConnectionStatus");
    assert(GetConnectionStatus && "Can't load GetConnectionStatus function from CCAPI.dll");

    if (ConnectConsole(ip) == CCAPI_OK)
        Notify(NotifyCaution, "Connected!");
    int status;
    GetConnectionStatus(&status);
    printf("Status connection: %s\n", status ? "Connected" : "Not connected");
    return (!status);
}
J'pense que vous avez tout compris ici à part sans doute
Code:
return (!status);
Explications
Si la console a réussi à se connecter alors status sera > 0, si je fais !status cela me retournera 0 si status != 0, pour pouvoir tester dans le main avec CCAPI_OK, j'aurais très bien pu aussi directement tester avec !=
Notre fonction ConnectConsole est maintenant terminé, votre main devrait ressembler à ça​
Code:
/*
* * Vos includes
*/
# include "main.h"
# include "ccapi.h"

int     main(void)
{
    const HINSTANCE CCAPI = LoadLibrary("CCAPI.dll");
    assert(CCAPI && "Move CCAPI.dll in executable path");

    const int ret_cc = ConnectConsole(CCAPI);
    assert(ret_cc == CCAPI_OK && "Can't connect to PS3");
..

V - Attacher le processus

Alors sur cette fonction, j'ai tout simplement copié/collé la fonction d'iMCSx en C#
1460924898-15.png

Voici comment je l'ai codé en C​
Code:
char                *GetProcessName(const HINSTANCE CCAPI, u32 pid)
{
    CCAPI_GetProcessName GetProcessName = (CCAPI_GetProcessName)GetProcAddress(CCAPI, "CCAPIGetProcessName");
    assert(GetProcessName && "Can't load GetProcessName function from CCAPI.dll");

    ProcessName name;
    if (GetProcessName(pid, &name) == CCAPI_OK)
        return (strdup(name.value));
    return (NULL);
}

bool                GetProcessList(const HINSTANCE CCAPI, u32 **pids, u32 *npid)
{
    CCAPI_GetProcessList GetProcessList = (CCAPI_GetProcessList)GetProcAddress(CCAPI, "CCAPIGetProcessList");
    assert(GetProcessList && "Can't load GetProcessList function from CCAPI.dll");

    GetProcessList(npid, 0);

    *pids = (u32 *)malloc(*npid * sizeof(u32));
    if (*pids)
    {
        if (GetProcessList(npid, *pids) == CCAPI_OK)
            return (true);
    }
    return (false);
}

bool                AttachProcess(const HINSTANCE CCAPI, u32 *pid)
{
    size_t  count;
    u32     *pids;
    char    *pname;

    bool result = GetProcessList(CCAPI, &pids, &count);
    if (!result)
        return (result);
    for (unsigned int i = 0; i < count; ++i)
    {
        if ((pname = GetProcessName(CCAPI, pids[i])))
        {
            if (!strstr(pname, "flash"))
            {
                *pid = pids[i];
                break;
            }
            else
                result = false;
        }
    }
    memdel((void **)&pids);
    return (result);
}
À partir de maintenant j'expliquerai donc beaucoup moins les choses voir pas du tout, là encore tout est expliqué sur la

Votre main devrait maintenant contenir une fonction de + : AttachProcess
Code:
int     main(void)
{
    const HINSTANCE CCAPI = LoadLibrary("CCAPI.dll");
    assert(CCAPI && "Move CCAPI.dll in executable path");

    const int ret_cc = ConnectConsole(CCAPI);
    assert(ret_cc == CCAPI_OK && "Can't connect to PS3");

    u32 pid;
    const bool ret_ap = AttachProcess(CCAPI, &pid);
    assert(ret_ap != CCAPI_OK && "Can't attach default process game");
..
VI - SetMemory

La fonction SetMemory tout bête !
Code:
int                 SetMemory(const HINSTANCE CCAPI, u32 pid, u64 offset, u32 size, const void *data)
{
    CCAPI_SetMemory SetMemory = (CCAPI_SetMemory)GetProcAddress(CCAPI, "CCAPISetMemory");
    assert(SetMemory && "Can't load SetMemory function from CCAPI.dll");

    return (SetMemory(pid, offset, size, data));
}

À partir de maintenant, vous pouvez changer votre prestige, stats vous faire un unlock all etc.. Enstone vous montre un (Rien ne vous empêche par la suite de programmer en fenêtre)

Fin
Voilà, le tuto s'arrête si tu as des questions n'hésite pas à commenter (no mp stp) et n'oublies pas de free la dll avec FreeLibrary : )

Voici ma source complète sur github qui contiendra un peu + de fonctions

1460933129-15.png


Crédits: iMCSx x Enstone x OpenClassroom x Stackoverflow
Certains diront " ctro compliké pr cke c ", c'est vrai mais c'est pour s'amuser ; )
ah bha x) tu explique le C tool ps3 bon topic mais le C++ reste mieux pour les tools :D je viens de release a l'instant ceci x) https://reality-gaming.fr/threads/release-rtm-c-ccapi-rpc-c-by-marent-and-mskx-and-enstone.540597/
 
ah bha x) tu explique le C tool ps3 bon topic mais le C++ reste mieux pour les tools :D je viens de release a l'instant ceci x) https://reality-gaming.fr/threads/release-rtm-c-ccapi-rpc-c-by-marent-and-mskx-and-enstone.540597/
Oh le même soir ! x)
 
Retour
Haut